diff --git a/LMEMappeCatastaliApp.csproj b/LMEMappeCatastaliApp.csproj
index 9f6e8a3..11bbc75 100644
--- a/LMEMappeCatastaliApp.csproj
+++ b/LMEMappeCatastaliApp.csproj
@@ -28,8 +28,8 @@
com.companyname.lmemappecatastaliapp
- 0.2.24
- 28
+ 0.2.25
+ 29
None
diff --git a/wwwroot/css/app.css b/wwwroot/css/app.css
index 8dae8a3..0848879 100644
--- a/wwwroot/css/app.css
+++ b/wwwroot/css/app.css
@@ -178,7 +178,7 @@ input[type="checkbox"] {
right: 12px;
z-index: 940;
display: grid;
- width: min(320px, calc(100% - 24px));
+ width: min(760px, 62vw, calc(100% - 24px));
max-height: calc(100% - 152px);
overflow-y: auto;
border: 1px solid var(--line);
@@ -283,11 +283,7 @@ input[type="checkbox"] {
list-style: none;
}
-.layer-manager-object > summary {
- grid-template-columns: 28px 20px minmax(0, 1fr) auto auto auto;
-}
-
-.layer-manager-renamable > summary {
+.layer-manager-with-actions > summary {
grid-template-columns: 28px 20px minmax(0, 1fr) auto auto auto;
}
@@ -310,7 +306,15 @@ input[type="checkbox"] {
cursor: grab;
}
-.layer-rename-button {
+.layer-row-actions {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: flex-end;
+ gap: 4px;
+}
+
+.layer-rename-button,
+.layer-remove-button {
min-height: 28px;
padding: 0 8px;
border: 1px solid #bfd4cd;
@@ -325,6 +329,16 @@ input[type="checkbox"] {
background: #d9eee7;
}
+.layer-remove-button {
+ border-color: #fecaca;
+ background: #fff1f2;
+ color: #b42318;
+}
+
+.layer-remove-button:active {
+ background: #ffe4e6;
+}
+
.layer-move-buttons {
display: inline-grid;
grid-template-columns: 24px 24px;
@@ -918,10 +932,31 @@ footer {
.map-layer-panel {
top: 68px;
right: 8px;
- width: min(320px, calc(100% - 16px));
+ width: calc(100% - 16px);
max-height: calc(100% - 144px);
}
+ .layer-manager-with-actions > summary {
+ grid-template-columns: 28px 20px minmax(0, 1fr) auto;
+ }
+
+ .layer-manager-with-actions > summary > .layer-row-actions {
+ grid-row: 2;
+ grid-column: 3;
+ justify-content: flex-start;
+ }
+
+ .layer-manager-with-actions > summary > .layer-move-buttons {
+ grid-row: 1;
+ grid-column: 4;
+ }
+
+ .layer-manager-with-actions > summary > .layer-manager-count {
+ grid-row: 2;
+ grid-column: 4;
+ justify-self: end;
+ }
+
.tool-sheet {
top: 10%;
bottom: var(--nav-height);
@@ -980,6 +1015,12 @@ footer {
}
}
+@media (min-width: 701px) and (max-width: 1100px) {
+ .map-layer-panel {
+ width: min(680px, calc(100% - 24px));
+ }
+}
+
@media (max-width: 380px) {
.app-identity span {
display: none;
diff --git a/wwwroot/js/lme-map.js b/wwwroot/js/lme-map.js
index 390b940..9c0e7f3 100644
--- a/wwwroot/js/lme-map.js
+++ b/wwwroot/js/lme-map.js
@@ -61,6 +61,7 @@ const lmeState = {
managerHiddenMeasurementSummaryIds: new Set(),
managerHiddenMeasurementSideIds: new Set(),
managerHiddenCategories: new Set(),
+ managerRemovedCategories: new Set(),
managerObjectOrder: {},
managerCategoryNames: {},
managerExpandedRows: new Set(),
@@ -1251,6 +1252,60 @@ function renameManagedBlock(category, source, records) {
setInfo(`Gruppo rinominato: ${name}.`);
}
+function managedCategoryCanRemove(category, records) {
+ return records.length > 0
+ && ["drawings", "imported", "importedSheets", "selectedParcels", "gpsParcels"].includes(category.key);
+}
+
+function managedObjectCanRemove(record) {
+ return ["drawings", "imported", "importedSheets", "selectedParcels", "gpsParcels"].includes(record.categoryKey);
+}
+
+function layerManagerRowActions(renameButton, removeButton) {
+ if (!renameButton && !removeButton) {
+ return "";
+ }
+ return `${renameButton}${removeButton}`;
+}
+
+function removeManagedRecords(records, subject) {
+ if (!records.length) {
+ return;
+ }
+ const message = records.length === 1
+ ? `Rimuovere ${subject} dal progetto? Non verra incluso nel prossimo salvataggio.`
+ : `Rimuovere ${subject} e tutti i suoi ${records.length} oggetti dal progetto? Non verranno inclusi nel prossimo salvataggio.`;
+ if (!window.confirm(message)) {
+ return;
+ }
+ const removedIds = new Set(records.map(record => record.id));
+ const categoryKeys = new Set(records.map(record => record.categoryKey));
+ records.forEach(record => {
+ if (record.parent?.hasLayer?.(record.layer)) {
+ record.parent.removeLayer(record.layer);
+ }
+ lmeState.managerHiddenObjects.delete(record.id);
+ lmeState.managerHiddenObjectIds.delete(record.id);
+ lmeState.managerHiddenMeasurementSummaryIds.delete(record.id);
+ lmeState.managerHiddenMeasurementSideIds.delete(record.id);
+ });
+ categoryKeys.forEach(categoryKey => {
+ const order = lmeState.managerObjectOrder[categoryKey] || [];
+ lmeState.managerObjectOrder[categoryKey] = order.filter(id => !removedIds.has(id));
+ const category = layerManagerCategories().find(item => item.key === categoryKey);
+ if (category && managedRecordsForCategory(category).length === 0) {
+ lmeState.managerRemovedCategories.add(categoryKey);
+ delete lmeState.managerCategoryNames[categoryKey];
+ }
+ });
+ clearManagerHighlight();
+ refreshImportedMeasurements();
+ refreshDrawingMeasurements();
+ updateGpsInsideState();
+ refreshLayerManager();
+ setInfo(`${records.length === 1 ? "Oggetto rimosso" : `${records.length} oggetti rimossi`} dal progetto.`);
+}
+
function managedObjectDetails(layer) {
const details = [];
const properties = layer?.feature?.properties || {};
@@ -1306,6 +1361,11 @@ function refreshLayerManager() {
return;
}
const records = managedRecordsForCategory(category);
+ if (records.length) {
+ lmeState.managerRemovedCategories.delete(category.key);
+ } else if (lmeState.managerRemovedCategories.has(category.key)) {
+ return;
+ }
const savedOrder = lmeState.managerObjectOrder[category.key] || [];
const positions = new Map(savedOrder.map((id, index) => [id, index]));
records.sort((left, right) =>
@@ -1334,12 +1394,16 @@ function renderLayerManagerCategory(category, records) {
const renameButton = managedCategoryCanRename(category)
? ``
: "";
- group.classList.toggle("layer-manager-renamable", Boolean(renameButton));
+ const removeButton = managedCategoryCanRemove(category, records)
+ ? ``
+ : "";
+ const rowActions = layerManagerRowActions(renameButton, removeButton);
+ group.classList.toggle("layer-manager-with-actions", Boolean(rowActions));
const visibleCount = records.filter(record => !lmeState.managerHiddenObjectIds.has(record.id)).length;
const categoryVisible = !lmeState.managerHiddenCategories.has(category.key)
&& (!category.roots.length || category.roots.some(layer => lmeState.map.hasLayer(layer)));
const visible = categoryVisible;
- group.innerHTML = `${escapeHtml(categoryName)}${renameButton}${layerManagerMoveButtons("gruppo")}${records.length}
`;
+ group.innerHTML = `${escapeHtml(categoryName)}${rowActions}${layerManagerMoveButtons("gruppo")}${records.length}`;
const checkbox = group.querySelector("input");
checkbox.indeterminate = categoryVisible && records.length > 0 && visibleCount < records.length;
checkbox.addEventListener("click", event => event.stopPropagation());
@@ -1349,6 +1413,11 @@ function renderLayerManagerCategory(category, records) {
event.stopPropagation();
renameManagedCategory(category, records);
});
+ group.querySelector(".layer-remove-button")?.addEventListener("click", event => {
+ event.preventDefault();
+ event.stopPropagation();
+ removeManagedRecords(records, `il gruppo '${categoryName}'`);
+ });
bindManagedParentHighlight(group, `category:${category.key}`, records);
const children = group.querySelector(".layer-manager-children");
if (category.blocks) {
@@ -1375,8 +1444,11 @@ function renderLayerManagerBlock(category, source, records) {
const visibleCount = records.filter(record => !lmeState.managerHiddenObjectIds.has(record.id)).length;
const visible = visibleCount === records.length;
const blockName = managedBlockName(source, records);
- block.classList.add("layer-manager-renamable");
- block.innerHTML = `${escapeHtml(blockName)}${layerManagerMoveButtons("blocco")}${records.length}`;
+ const rowActions = layerManagerRowActions(
+ ``,
+ ``);
+ block.classList.add("layer-manager-with-actions");
+ block.innerHTML = `${escapeHtml(blockName)}${rowActions}${layerManagerMoveButtons("blocco")}${records.length}`;
const checkbox = block.querySelector("input");
checkbox.indeterminate = visibleCount > 0 && !visible;
checkbox.addEventListener("click", event => event.stopPropagation());
@@ -1389,6 +1461,11 @@ function renderLayerManagerBlock(category, source, records) {
event.stopPropagation();
renameManagedBlock(category, source, records);
});
+ block.querySelector(".layer-remove-button").addEventListener("click", event => {
+ event.preventDefault();
+ event.stopPropagation();
+ removeManagedRecords(records, `il gruppo '${blockName}'`);
+ });
bindManagedParentHighlight(block, `block:${category.key}:${source}`, records);
const children = block.querySelector(".layer-manager-children");
records.forEach((record, index) => children.appendChild(renderLayerManagerObject(record, index)));
@@ -1408,7 +1485,13 @@ function renderLayerManagerObject(record, index) {
const renameButton = managedObjectCanRename(record)
? ``
: "";
- object.innerHTML = `${escapeHtml(managedObjectLabel(record, index))}${renameButton}${layerManagerMoveButtons("oggetto")}›`;
+ const removeButton = managedObjectCanRemove(record)
+ ? ``
+ : "";
+ const rowActions = layerManagerRowActions(renameButton, removeButton);
+ object.classList.toggle("layer-manager-with-actions", Boolean(rowActions));
+ const objectName = managedObjectLabel(record, index);
+ object.innerHTML = `${escapeHtml(objectName)}${rowActions}${layerManagerMoveButtons("oggetto")}›`;
const checkbox = object.querySelector("input");
checkbox.addEventListener("click", event => event.stopPropagation());
checkbox.addEventListener("change", () => setManagedObjectVisible(record, checkbox.checked, true));
@@ -1417,6 +1500,11 @@ function renderLayerManagerObject(record, index) {
event.stopPropagation();
renameManagedObject(record, index);
});
+ object.querySelector(".layer-remove-button")?.addEventListener("click", event => {
+ event.preventDefault();
+ event.stopPropagation();
+ removeManagedRecords([record], `'${objectName}'`);
+ });
object.querySelector(".layer-manager-title").addEventListener("click", event => {
event.preventDefault();
event.stopPropagation();
@@ -2695,6 +2783,7 @@ function captureDisplayOptions() {
layerOrder: [...lmeState.layerOrder],
layerObjectOrder: { ...lmeState.managerObjectOrder },
layerCategoryNames: { ...lmeState.managerCategoryNames },
+ removedLayerCategories: [...lmeState.managerRemovedCategories],
hiddenLayerObjects: [...lmeState.managerHiddenObjectIds],
hiddenLayerMeasurementSummaries: [...lmeState.managerHiddenMeasurementSummaryIds],
hiddenLayerMeasurementSides: [...lmeState.managerHiddenMeasurementSideIds],
@@ -2734,6 +2823,9 @@ function applyProjectDisplayOptions(options) {
if (options.layerCategoryNames && typeof options.layerCategoryNames === "object") {
lmeState.managerCategoryNames = { ...options.layerCategoryNames };
}
+ if (Array.isArray(options.removedLayerCategories)) {
+ lmeState.managerRemovedCategories = new Set(options.removedLayerCategories);
+ }
if (Array.isArray(options.hiddenLayerObjects)) {
lmeState.managerHiddenObjectIds = new Set(options.hiddenLayerObjects);
}
@@ -2835,6 +2927,7 @@ function resetLayerManagerProjectState() {
lmeState.managerHiddenMeasurementSummaryIds.clear();
lmeState.managerHiddenMeasurementSideIds.clear();
lmeState.managerHiddenCategories.clear();
+ lmeState.managerRemovedCategories.clear();
lmeState.managerObjectOrder = {};
lmeState.managerCategoryNames = {};
clearManagerHighlight();