|
|
|
|
@ -2133,6 +2133,31 @@ HTML = """<!doctype html>
|
|
|
|
|
const scale = Math.max(.5, Math.min(2, Math.sqrt(area) * block._configUserScale));
|
|
|
|
|
block.style.setProperty('--block-scale', scale.toFixed(3));
|
|
|
|
|
}
|
|
|
|
|
function resolveConfigOverlaps() {
|
|
|
|
|
const gap = 14;
|
|
|
|
|
const items = configBlocks.filter(block => block && !configBlockState(block)).sort((a, b) => {
|
|
|
|
|
const top = (block => parseFloat(block.style.top) || block.offsetTop || 0);
|
|
|
|
|
return top(a) - top(b) || (parseFloat(a.style.left) || a.offsetLeft || 0) - (parseFloat(b.style.left) || b.offsetLeft || 0);
|
|
|
|
|
});
|
|
|
|
|
let moved = false;
|
|
|
|
|
items.forEach((block, index) => {
|
|
|
|
|
let top = parseFloat(block.style.top) || block.offsetTop || 0;
|
|
|
|
|
const left = parseFloat(block.style.left) || block.offsetLeft || 0;
|
|
|
|
|
const width = block.offsetWidth;
|
|
|
|
|
const height = block.offsetHeight;
|
|
|
|
|
items.slice(0, index).forEach(previous => {
|
|
|
|
|
const previousLeft = parseFloat(previous.style.left) || previous.offsetLeft || 0;
|
|
|
|
|
const previousTop = parseFloat(previous.style.top) || previous.offsetTop || 0;
|
|
|
|
|
const horizontal = left < previousLeft + previous.offsetWidth && previousLeft < left + width;
|
|
|
|
|
if (horizontal && top < previousTop + previous.offsetHeight + gap && top + height > previousTop) top = previousTop + previous.offsetHeight + gap;
|
|
|
|
|
});
|
|
|
|
|
if (top <= (parseFloat(block.style.top) || block.offsetTop || 0) + .5) return;
|
|
|
|
|
block.style.top = `${Math.round(top)}px`;
|
|
|
|
|
captureConfigLayout(block);
|
|
|
|
|
moved = true;
|
|
|
|
|
});
|
|
|
|
|
return moved;
|
|
|
|
|
}
|
|
|
|
|
function applyConfigContentScale(value) {
|
|
|
|
|
configContentScale = Math.max(.5, Math.min(2, (Number(value) || 100) / 100));
|
|
|
|
|
const block = selectedConfigBlock;
|
|
|
|
|
@ -2145,6 +2170,8 @@ HTML = """<!doctype html>
|
|
|
|
|
setText('configContentScaleValue', `${Math.round(configContentScale * 100)}%`);
|
|
|
|
|
updateConfigBlockScale(block);
|
|
|
|
|
updateConfigScaleToggle(block);
|
|
|
|
|
resolveConfigOverlaps();
|
|
|
|
|
updateConfigCanvasHeight();
|
|
|
|
|
saveConfigLayout();
|
|
|
|
|
}
|
|
|
|
|
function updateConfigScaleToggle(block) {
|
|
|
|
|
@ -2316,7 +2343,8 @@ HTML = """<!doctype html>
|
|
|
|
|
});
|
|
|
|
|
let fitted = false;
|
|
|
|
|
configBlocks.forEach(block => { fitted = fitConfigBlockContent(block) || fitted; updateConfigBlockScale(block); });
|
|
|
|
|
if (fitted) saveConfigLayout();
|
|
|
|
|
const separated = resolveConfigOverlaps();
|
|
|
|
|
if (fitted || separated) saveConfigLayout();
|
|
|
|
|
updateConfigCanvasHeight();
|
|
|
|
|
}
|
|
|
|
|
function setConfigBlockStates(blocks, state) {
|
|
|
|
|
@ -2562,6 +2590,7 @@ HTML = """<!doctype html>
|
|
|
|
|
group.forEach(item => captureConfigLayout(item));
|
|
|
|
|
if (droppedOnTrash) setConfigBlockStates(group, 'deleted');
|
|
|
|
|
else {
|
|
|
|
|
resolveConfigOverlaps();
|
|
|
|
|
saveConfigLayout();
|
|
|
|
|
setText('configLayoutState', `${configBlocks.length - configBlocks.filter(item => configBlockState(item)).length} блоков · раскладка сохранена`);
|
|
|
|
|
}
|
|
|
|
|
@ -2678,6 +2707,7 @@ HTML = """<!doctype html>
|
|
|
|
|
block.removeEventListener('pointercancel', end);
|
|
|
|
|
block.classList.remove('is-resizing');
|
|
|
|
|
captureConfigLayout(block);
|
|
|
|
|
resolveConfigOverlaps();
|
|
|
|
|
saveConfigLayout();
|
|
|
|
|
block._suppressSummaryClick = true;
|
|
|
|
|
window.setTimeout(() => { block._suppressSummaryClick = false; }, 0);
|
|
|
|
|
@ -2910,6 +2940,31 @@ HTML = """<!doctype html>
|
|
|
|
|
block._networkUserScale = Math.max(.5, Math.min(2, userScale));
|
|
|
|
|
block.style.setProperty('--block-scale', Math.max(.5, Math.min(2, Math.sqrt(area) * block._networkUserScale)).toFixed(3));
|
|
|
|
|
}
|
|
|
|
|
function resolveNetworkOverlaps() {
|
|
|
|
|
const gap = 14;
|
|
|
|
|
const items = networkBlocks.filter(block => block && !networkState(block)).sort((a, b) => {
|
|
|
|
|
const top = block => parseFloat(block.style.top) || block.offsetTop || 0;
|
|
|
|
|
return top(a) - top(b) || (parseFloat(a.style.left) || a.offsetLeft || 0) - (parseFloat(b.style.left) || b.offsetLeft || 0);
|
|
|
|
|
});
|
|
|
|
|
let moved = false;
|
|
|
|
|
items.forEach((block, index) => {
|
|
|
|
|
let top = parseFloat(block.style.top) || block.offsetTop || 0;
|
|
|
|
|
const left = parseFloat(block.style.left) || block.offsetLeft || 0;
|
|
|
|
|
const width = block.offsetWidth;
|
|
|
|
|
const height = block.offsetHeight;
|
|
|
|
|
items.slice(0, index).forEach(previous => {
|
|
|
|
|
const previousLeft = parseFloat(previous.style.left) || previous.offsetLeft || 0;
|
|
|
|
|
const previousTop = parseFloat(previous.style.top) || previous.offsetTop || 0;
|
|
|
|
|
const horizontal = left < previousLeft + previous.offsetWidth && previousLeft < left + width;
|
|
|
|
|
if (horizontal && top < previousTop + previous.offsetHeight + gap && top + height > previousTop) top = previousTop + previous.offsetHeight + gap;
|
|
|
|
|
});
|
|
|
|
|
if (top <= (parseFloat(block.style.top) || block.offsetTop || 0) + .5) return;
|
|
|
|
|
block.style.top = `${Math.round(top)}px`;
|
|
|
|
|
captureNetworkLayout(block);
|
|
|
|
|
moved = true;
|
|
|
|
|
});
|
|
|
|
|
return moved;
|
|
|
|
|
}
|
|
|
|
|
function selectNetworkBlock(block) {
|
|
|
|
|
selectedNetworkBlocks = new Set(block && !networkState(block) ? [block] : []);
|
|
|
|
|
updateNetworkSelection(block);
|
|
|
|
|
@ -2953,6 +3008,8 @@ HTML = """<!doctype html>
|
|
|
|
|
setText('networkContentScaleValue', `${Math.round(networkContentScale * 100)}%`);
|
|
|
|
|
updateNetworkBlockScale(block);
|
|
|
|
|
updateNetworkScaleToggle(block);
|
|
|
|
|
resolveNetworkOverlaps();
|
|
|
|
|
updateNetworkCanvasHeight();
|
|
|
|
|
saveNetworkLayout();
|
|
|
|
|
}
|
|
|
|
|
function updateNetworkScaleToggle(block) {
|
|
|
|
|
@ -3022,6 +3079,8 @@ HTML = """<!doctype html>
|
|
|
|
|
if (Number.isFinite(Number(entry.z))) { block.style.zIndex = String(Math.max(1, Number(entry.z))); networkZIndex = Math.max(networkZIndex, Number(entry.z)); }
|
|
|
|
|
updateNetworkBlockScale(block);
|
|
|
|
|
});
|
|
|
|
|
const separated = resolveNetworkOverlaps();
|
|
|
|
|
if (separated) saveNetworkLayout();
|
|
|
|
|
updateNetworkCanvasHeight();
|
|
|
|
|
}
|
|
|
|
|
function bringNetworkBlockFront(block) {
|
|
|
|
|
@ -3219,7 +3278,7 @@ HTML = """<!doctype html>
|
|
|
|
|
if (!dragged) return;
|
|
|
|
|
group.forEach(item => captureNetworkLayout(item));
|
|
|
|
|
if (droppedOnTrash) setNetworkBlockStates(group, 'deleted');
|
|
|
|
|
else { saveNetworkLayout(); renderNetworkStructure(); }
|
|
|
|
|
else { resolveNetworkOverlaps(); saveNetworkLayout(); renderNetworkStructure(); }
|
|
|
|
|
group.forEach(item => {
|
|
|
|
|
item._networkSuppressClick = true;
|
|
|
|
|
window.setTimeout(() => { item._networkSuppressClick = false; }, 0);
|
|
|
|
|
@ -3370,6 +3429,7 @@ HTML = """<!doctype html>
|
|
|
|
|
block.removeEventListener('pointercancel', end);
|
|
|
|
|
block.classList.remove('is-resizing');
|
|
|
|
|
captureNetworkLayout(block);
|
|
|
|
|
resolveNetworkOverlaps();
|
|
|
|
|
saveNetworkLayout();
|
|
|
|
|
block._networkSuppressClick = true;
|
|
|
|
|
window.setTimeout(() => { block._networkSuppressClick = false; }, 0);
|
|
|
|
|
|