|
|
|
@ -1309,6 +1309,7 @@ HTML = """<!doctype html>
|
|
|
|
.config-restore-panel[hidden], .config-trash[hidden] { display: none !important; }
|
|
|
|
.config-restore-panel[hidden], .config-trash[hidden] { display: none !important; }
|
|
|
|
.config-canvas { position: relative; display: block; min-height: 760px; padding: 8px 6px 18px; overflow: auto; overscroll-behavior: contain; }
|
|
|
|
.config-canvas { position: relative; display: block; min-height: 760px; padding: 8px 6px 18px; overflow: auto; overscroll-behavior: contain; }
|
|
|
|
.config-canvas > .config-block { position: absolute; box-sizing: border-box; container: config-block / inline-size; margin: 0; min-width: 240px; min-height: 110px; border: 1px solid var(--ui-border) !important; border-radius: 10px; background: var(--ui-panel) !important; box-shadow: 0 6px 18px rgba(0, 0, 0, .1); overflow: auto; transition: border-color .2s ease, box-shadow .2s ease, opacity .2s ease; }
|
|
|
|
.config-canvas > .config-block { position: absolute; box-sizing: border-box; container: config-block / inline-size; margin: 0; min-width: 240px; min-height: 110px; border: 1px solid var(--ui-border) !important; border-radius: 10px; background: var(--ui-panel) !important; box-shadow: 0 6px 18px rgba(0, 0, 0, .1); overflow: auto; transition: border-color .2s ease, box-shadow .2s ease, opacity .2s ease; }
|
|
|
|
|
|
|
|
.config-canvas > .config-block { cursor: grab; touch-action: none; }
|
|
|
|
.config-canvas > .config-block:hover { border-color: color-mix(in srgb, var(--ui-accent) 45%, var(--ui-border)) !important; }
|
|
|
|
.config-canvas > .config-block:hover { border-color: color-mix(in srgb, var(--ui-accent) 45%, var(--ui-border)) !important; }
|
|
|
|
.config-canvas > .config-block.is-dragging, .config-canvas > .config-block.is-resizing { z-index: 5; border-color: var(--ui-accent) !important; box-shadow: 0 10px 28px color-mix(in srgb, var(--ui-accent) 16%, transparent); transition: none; }
|
|
|
|
.config-canvas > .config-block.is-dragging, .config-canvas > .config-block.is-resizing { z-index: 5; border-color: var(--ui-accent) !important; box-shadow: 0 10px 28px color-mix(in srgb, var(--ui-accent) 16%, transparent); transition: none; }
|
|
|
|
.config-canvas > .config-custom-block { border-style: dashed !important; }
|
|
|
|
.config-canvas > .config-custom-block { border-style: dashed !important; }
|
|
|
|
@ -1318,6 +1319,8 @@ HTML = """<!doctype html>
|
|
|
|
.config-block > summary { cursor: grab; touch-action: none; }
|
|
|
|
.config-block > summary { cursor: grab; touch-action: none; }
|
|
|
|
.config-block > summary:active, .config-block.is-dragging > summary { cursor: grabbing; }
|
|
|
|
.config-block > summary:active, .config-block.is-dragging > summary { cursor: grabbing; }
|
|
|
|
.config-block.is-dragging, .config-block.is-resizing { user-select: none; }
|
|
|
|
.config-block.is-dragging, .config-block.is-resizing { user-select: none; }
|
|
|
|
|
|
|
|
.config-block.is-dragging { cursor: grabbing; }
|
|
|
|
|
|
|
|
.config-block input, .config-block select, .config-block textarea, .config-block button, .config-block a { cursor: auto; touch-action: auto; }
|
|
|
|
.config-block label, .config-block input, .config-block select, .config-block button, .config-block pre { min-width: 0; max-width: 100%; box-sizing: border-box; }
|
|
|
|
.config-block label, .config-block input, .config-block select, .config-block button, .config-block pre { min-width: 0; max-width: 100%; box-sizing: border-box; }
|
|
|
|
.config-block .control-fields, .config-block .advanced-grid, .config-block .packet-grid, .config-block .packet-field-list { min-width: 0; }
|
|
|
|
.config-block .control-fields, .config-block .advanced-grid, .config-block .packet-grid, .config-block .packet-field-list { min-width: 0; }
|
|
|
|
@container config-block (max-width: 620px) {
|
|
|
|
@container config-block (max-width: 620px) {
|
|
|
|
@ -2237,7 +2240,7 @@ HTML = """<!doctype html>
|
|
|
|
block.addEventListener('pointerdown', event => {
|
|
|
|
block.addEventListener('pointerdown', event => {
|
|
|
|
bringConfigBlockFront(block);
|
|
|
|
bringConfigBlockFront(block);
|
|
|
|
const edge = configResizeEdge(event, block);
|
|
|
|
const edge = configResizeEdge(event, block);
|
|
|
|
if (!edge || (event.target.closest('summary') && !edge.includes('n'))) return;
|
|
|
|
if (!edge || configDragBlocked(block, event)) return;
|
|
|
|
event.preventDefault();
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
event.stopPropagation();
|
|
|
|
const startX = event.clientX;
|
|
|
|
const startX = event.clientX;
|
|
|
|
@ -2290,41 +2293,9 @@ HTML = """<!doctype html>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
block.addEventListener('pointerleave', () => { if (!block.classList.contains('is-resizing')) block.style.cursor = ''; });
|
|
|
|
block.addEventListener('pointerleave', () => { if (!block.classList.contains('is-resizing')) block.style.cursor = ''; });
|
|
|
|
summary.addEventListener('pointerdown', event => {
|
|
|
|
block.addEventListener('pointerdown', event => {
|
|
|
|
if (event.button !== 0 || !configCanvas) return;
|
|
|
|
if (event.defaultPrevented || block.classList.contains('is-resizing')) return;
|
|
|
|
const startX = event.clientX;
|
|
|
|
startConfigBlockDrag(block, event);
|
|
|
|
const startY = event.clientY;
|
|
|
|
|
|
|
|
const startLeft = parseFloat(block.style.left) || block.offsetLeft || 0;
|
|
|
|
|
|
|
|
const startTop = parseFloat(block.style.top) || block.offsetTop || 0;
|
|
|
|
|
|
|
|
let dragged = false;
|
|
|
|
|
|
|
|
summary.setPointerCapture?.(event.pointerId);
|
|
|
|
|
|
|
|
const move = moveEvent => {
|
|
|
|
|
|
|
|
if (!dragged && Math.hypot(moveEvent.clientX - startX, moveEvent.clientY - startY) < 4) return;
|
|
|
|
|
|
|
|
if (!dragged) {
|
|
|
|
|
|
|
|
dragged = true;
|
|
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
block.classList.add('is-dragging');
|
|
|
|
|
|
|
|
const trash = $('configTrash');
|
|
|
|
|
|
|
|
if (trash) { trash.hidden = false; trash.classList.remove('is-over'); }
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
const maxLeft = Math.max(0, configCanvasWidth() - block.offsetWidth);
|
|
|
|
|
|
|
|
block.style.left = `${Math.max(0, Math.min(maxLeft, Math.round(startLeft + moveEvent.clientX - startX)))}px`;
|
|
|
|
|
|
|
|
block.style.top = `${Math.max(0, Math.round(startTop + moveEvent.clientY - startY))}px`;
|
|
|
|
|
|
|
|
setTrashHover(moveEvent);
|
|
|
|
|
|
|
|
updateConfigCanvasHeight();
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
const end = endEvent => {
|
|
|
|
|
|
|
|
summary.releasePointerCapture?.(event.pointerId);
|
|
|
|
|
|
|
|
summary.removeEventListener('pointermove', move);
|
|
|
|
|
|
|
|
summary.removeEventListener('pointerup', end);
|
|
|
|
|
|
|
|
summary.removeEventListener('pointercancel', end);
|
|
|
|
|
|
|
|
block.classList.remove('is-dragging');
|
|
|
|
|
|
|
|
finishConfigDrag(block, endEvent, dragged);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
summary.addEventListener('pointermove', move);
|
|
|
|
|
|
|
|
summary.addEventListener('pointerup', end, {once: true});
|
|
|
|
|
|
|
|
summary.addEventListener('pointercancel', end, {once: true});
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
|
block.addEventListener('toggle', () => {
|
|
|
|
block.addEventListener('toggle', () => {
|
|
|
|
if (!block.open) block.open = true;
|
|
|
|
if (!block.open) block.open = true;
|
|
|
|
@ -2332,6 +2303,51 @@ HTML = """<!doctype html>
|
|
|
|
updateConfigCanvasHeight();
|
|
|
|
updateConfigCanvasHeight();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function configDragBlocked(block, event) {
|
|
|
|
|
|
|
|
const target = event.target;
|
|
|
|
|
|
|
|
if (!(target instanceof Element)) return true;
|
|
|
|
|
|
|
|
const summary = block.firstElementChild;
|
|
|
|
|
|
|
|
const nestedSummary = target.closest('summary');
|
|
|
|
|
|
|
|
if (nestedSummary && nestedSummary !== summary) return true;
|
|
|
|
|
|
|
|
if (nestedSummary === summary) return false;
|
|
|
|
|
|
|
|
return !!target.closest('input, select, textarea, button, a, [contenteditable="true"], .drop-zone, .packet-byte-map, .packet-field-row');
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function startConfigBlockDrag(block, event) {
|
|
|
|
|
|
|
|
if (event.button !== 0 || !configCanvas || configDragBlocked(block, event)) return;
|
|
|
|
|
|
|
|
const startX = event.clientX;
|
|
|
|
|
|
|
|
const startY = event.clientY;
|
|
|
|
|
|
|
|
const startLeft = parseFloat(block.style.left) || block.offsetLeft || 0;
|
|
|
|
|
|
|
|
const startTop = parseFloat(block.style.top) || block.offsetTop || 0;
|
|
|
|
|
|
|
|
let dragged = false;
|
|
|
|
|
|
|
|
block.setPointerCapture?.(event.pointerId);
|
|
|
|
|
|
|
|
const move = moveEvent => {
|
|
|
|
|
|
|
|
if (!dragged && Math.hypot(moveEvent.clientX - startX, moveEvent.clientY - startY) < 4) return;
|
|
|
|
|
|
|
|
if (!dragged) {
|
|
|
|
|
|
|
|
dragged = true;
|
|
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
block.classList.add('is-dragging');
|
|
|
|
|
|
|
|
const trash = $('configTrash');
|
|
|
|
|
|
|
|
if (trash) { trash.hidden = false; trash.classList.remove('is-over'); }
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
const maxLeft = Math.max(0, configCanvasWidth() - block.offsetWidth);
|
|
|
|
|
|
|
|
block.style.left = `${Math.max(0, Math.min(maxLeft, Math.round(startLeft + moveEvent.clientX - startX)))}px`;
|
|
|
|
|
|
|
|
block.style.top = `${Math.max(0, Math.round(startTop + moveEvent.clientY - startY))}px`;
|
|
|
|
|
|
|
|
setTrashHover(moveEvent);
|
|
|
|
|
|
|
|
updateConfigCanvasHeight();
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
const end = endEvent => {
|
|
|
|
|
|
|
|
block.releasePointerCapture?.(event.pointerId);
|
|
|
|
|
|
|
|
block.removeEventListener('pointermove', move);
|
|
|
|
|
|
|
|
block.removeEventListener('pointerup', end);
|
|
|
|
|
|
|
|
block.removeEventListener('pointercancel', end);
|
|
|
|
|
|
|
|
block.classList.remove('is-dragging');
|
|
|
|
|
|
|
|
finishConfigDrag(block, endEvent, dragged);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
block.addEventListener('pointermove', move);
|
|
|
|
|
|
|
|
block.addEventListener('pointerup', end, {once: true});
|
|
|
|
|
|
|
|
block.addEventListener('pointercancel', end, {once: true});
|
|
|
|
|
|
|
|
}
|
|
|
|
function resetConfigLayout() {
|
|
|
|
function resetConfigLayout() {
|
|
|
|
const custom = {};
|
|
|
|
const custom = {};
|
|
|
|
configBlocks.forEach(block => {
|
|
|
|
configBlocks.forEach(block => {
|
|
|
|
|