@@ -51,6 +51,10 @@ const lmeState = {
managerHighlight : null ,
managerHighlightedObjectId : null ,
managerHighlightedCategoryKey : null ,
managerHighlightedParentKey : null ,
managerHighlightedParentRecords : null ,
managerHoveredParentKey : null ,
managerHoveredParentRecords : null ,
managerOutsideSelectionBound : false ,
managerHiddenObjects : new Map ( ) ,
managerHiddenObjectIds : new Set ( ) ,
@@ -58,6 +62,7 @@ const lmeState = {
managerHiddenMeasurementSideIds : new Set ( ) ,
managerHiddenCategories : new Set ( ) ,
managerObjectOrder : { } ,
managerCategoryNames : { } ,
managerExpandedRows : new Set ( ) ,
dotNetReference : null
} ;
@@ -223,11 +228,13 @@ function init(dotNetReference) {
} ) ;
if ( ! lmeState . managerOutsideSelectionBound ) {
document . addEventListener ( "pointerdown" , event => {
if ( ! lmeState . managerHighlightedObjectId ) {
if ( ! lmeState . managerHighlightedObjectId && ! lmeState . managerHighlightedParentKey ) {
return ;
}
const selectedRow = event . target ? . closest ? . ( ".layer-manager-object" ) ;
if ( selectedRow ? . dataset . objectId === lmeState . managerHighlightedObjectId ) {
const selectedObject = event . target ? . closest ? . ( ".layer-manager-object" ) ;
const selectedParent = event . target ? . closest ? . ( "[data-highlight-key]" ) ;
if ( selectedObject ? . dataset . objectId === lmeState . managerHighlightedObjectId
|| selectedParent ? . dataset . highlightKey === lmeState . managerHighlightedParentKey ) {
return ;
}
clearManagerHighlight ( ) ;
@@ -1145,6 +1152,105 @@ function managedObjectLabel(record, index) {
return ` Oggetto ${ index + 1 } ` ;
}
function managedObjectEditableName ( record ) {
const properties = record ? . layer ? . feature ? . properties || { } ;
return properties . name || properties . Name || properties . label || properties . LABEL || "" ;
}
function managedObjectCanRename ( record ) {
return [ "drawings" , "imported" , "importedSheets" ] . includes ( record . categoryKey )
&& record . layer ? . feature ? . properties ;
}
function renameManagedObject ( record , index ) {
if ( ! managedObjectCanRename ( record ) ) {
return ;
}
const currentName = String ( managedObjectEditableName ( record ) || managedObjectLabel ( record , index ) ) . trim ( ) ;
const requestedName = window . prompt ( "Nuovo nome oggetto" , currentName ) ;
if ( requestedName === null ) {
return ;
}
const name = requestedName . trim ( ) . slice ( 0 , 120 ) ;
if ( ! name ) {
setInfo ( "Nome non modificato: inserisci un testo." ) ;
return ;
}
const properties = record . layer . feature . properties ;
properties . name = name ;
record . layer . lmeManagerLabel = record . categoryKey === "drawings" && record . layer instanceof L . Marker
? ` POI: ${ name } `
: null ;
updateStoredFeaturePopup ( record . layer ) ;
refreshImportedMeasurements ( ) ;
refreshDrawingMeasurements ( ) ;
refreshLayerManager ( ) ;
setInfo ( ` Oggetto rinominato: ${ name } . ` ) ;
}
function managedCategoryName ( category , records ) {
const storedName = lmeState . managerCategoryNames [ category . key ] ;
const featureName = records
. map ( record => record . layer ? . feature ? . properties ? . _lmeCategoryName )
. find ( Boolean ) ;
const name = String ( storedName || featureName || category . label ) . trim ( ) ;
if ( name !== category . label ) {
lmeState . managerCategoryNames [ category . key ] = name ;
}
return name ;
}
function managedCategoryCanRename ( category ) {
return [ "drawings" , "imported" , "importedSheets" ] . includes ( category . key ) ;
}
function renameManagedCategory ( category , records ) {
const currentName = managedCategoryName ( category , records ) ;
const requestedName = window . prompt ( "Nuovo nome gruppo" , currentName ) ;
if ( requestedName === null ) {
return ;
}
const name = requestedName . trim ( ) . slice ( 0 , 120 ) ;
if ( ! name ) {
setInfo ( "Nome non modificato: inserisci un testo." ) ;
return ;
}
lmeState . managerCategoryNames [ category . key ] = name ;
records . forEach ( record => {
if ( record . layer ? . feature ? . properties ) {
record . layer . feature . properties . _lmeCategoryName = name ;
}
} ) ;
refreshLayerManager ( ) ;
setInfo ( ` Gruppo rinominato: ${ name } . ` ) ;
}
function managedBlockName ( source , records ) {
return String ( records
. map ( record => record . layer ? . feature ? . properties ? . _lmeGroupName )
. find ( Boolean ) || source ) ;
}
function renameManagedBlock ( category , source , records ) {
const currentName = managedBlockName ( source , records ) ;
const requestedName = window . prompt ( "Nuovo nome gruppo" , currentName ) ;
if ( requestedName === null ) {
return ;
}
const name = requestedName . trim ( ) . slice ( 0 , 120 ) ;
if ( ! name ) {
setInfo ( "Nome non modificato: inserisci un testo." ) ;
return ;
}
records . forEach ( record => {
if ( record . layer ? . feature ? . properties ) {
record . layer . feature . properties . _lmeGroupName = name ;
}
} ) ;
refreshLayerManager ( ) ;
setInfo ( ` Gruppo rinominato: ${ name } . ` ) ;
}
function managedObjectDetails ( layer ) {
const details = [ ] ;
const properties = layer ? . feature ? . properties || { } ;
@@ -1224,15 +1330,26 @@ function renderLayerManagerCategory(category, records) {
group . dataset . dragType = "category" ;
group . dataset . categoryKey = category . key ;
bindLayerManagerExpansion ( group , ` category: ${ category . key } ` ) ;
const categoryName = managedCategoryName ( category , records ) ;
const renameButton = managedCategoryCanRename ( category )
? ` <button type="button" class="layer-rename-button" aria-label="Rinomina gruppo" title="Rinomina">Rinomina</button> `
: "" ;
group . classList . toggle ( "layer-manager-renamable" , Boolean ( renameButton ) ) ;
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 = ` <summary><button type="button" class="layer-drag-handle" aria-label="Trascina gruppo">☰</button><input type="checkbox" ${ visible ? "checked" : "" } aria-label="Mostra ${ escapeHtml ( category . label ) } "><span class="layer-manager-title"> ${ escapeHtml ( category . label ) } </span> ${ layerManagerMoveButtons ( "gruppo" ) } <span class="layer-manager-count"> ${ records . length } </span></summary><div class="layer-manager-children"></div> ` ;
group . innerHTML = ` <summary><button type="button" class="layer-drag-handle" aria-label="Trascina gruppo">☰</button><input type="checkbox" ${ visible ? "checked" : "" } aria-label="Mostra ${ escapeHtml ( categoryName ) } "><span class="layer-manager-title"> ${ escapeHtml ( categoryName ) } </span> ${ renameButton } ${ layerManagerMoveButtons ( "gruppo" ) } <span class="layer-manager-count"> ${ records . length } </span></summary><div class="layer-manager-children"></div> ` ;
const checkbox = group . querySelector ( "input" ) ;
checkbox . indeterminate = categoryVisible && records . length > 0 && visibleCount < records . length ;
checkbox . addEventListener ( "click" , event => event . stopPropagation ( ) ) ;
checkbox . addEventListener ( "change" , ( ) => setManagedCategoryVisible ( category , checkbox . checked ) ) ;
group . querySelector ( ".layer-rename-button" ) ? . addEventListener ( "click" , event => {
event . preventDefault ( ) ;
event . stopPropagation ( ) ;
renameManagedCategory ( category , records ) ;
} ) ;
bindManagedParentHighlight ( group , ` category: ${ category . key } ` , records ) ;
const children = group . querySelector ( ".layer-manager-children" ) ;
if ( category . blocks ) {
const blocks = new Map ( ) ;
@@ -1257,7 +1374,9 @@ function renderLayerManagerBlock(category, source, records) {
bindLayerManagerExpansion ( block , ` block: ${ category . key } : ${ source } ` ) ;
const visibleCount = records . filter ( record => ! lmeState . managerHiddenObjectIds . has ( record . id ) ) . length ;
const visible = visibleCount === records . length ;
block . innerHTML = ` <summary><button type="button" class="layer-drag-handle" aria-label="Trascina blocco">☰</button><input type="checkbox" ${ visible ? "checked" : "" } aria-label="Mostra blocco"><span class="layer-manager-title"> ${ escapeHtml ( source ) } </span> ${ layerManagerMoveButtons ( "blocco" ) } <span class="layer-manager-count"> ${ records . length } </span></summary><div class="layer-manager-children"></div> ` ;
const blockName = managedBlockName ( source , records ) ;
block . classList . add ( "layer-manager-renamable" ) ;
block . innerHTML = ` <summary><button type="button" class="layer-drag-handle" aria-label="Trascina blocco">☰</button><input type="checkbox" ${ visible ? "checked" : "" } aria-label="Mostra ${ escapeHtml ( blockName ) } "><span class="layer-manager-title"> ${ escapeHtml ( blockName ) } </span><button type="button" class="layer-rename-button" aria-label="Rinomina gruppo" title="Rinomina">Rinomina</button> ${ layerManagerMoveButtons ( "blocco" ) } <span class="layer-manager-count"> ${ records . length } </span></summary><div class="layer-manager-children"></div> ` ;
const checkbox = block . querySelector ( "input" ) ;
checkbox . indeterminate = visibleCount > 0 && ! visible ;
checkbox . addEventListener ( "click" , event => event . stopPropagation ( ) ) ;
@@ -1265,6 +1384,12 @@ function renderLayerManagerBlock(category, source, records) {
records . forEach ( record => setManagedObjectVisible ( record , checkbox . checked , false ) ) ;
refreshLayerManager ( ) ;
} ) ;
block . querySelector ( ".layer-rename-button" ) . addEventListener ( "click" , event => {
event . preventDefault ( ) ;
event . stopPropagation ( ) ;
renameManagedBlock ( category , source , records ) ;
} ) ;
bindManagedParentHighlight ( block , ` block: ${ category . key } : ${ source } ` , records ) ;
const children = block . querySelector ( ".layer-manager-children" ) ;
records . forEach ( ( record , index ) => children . appendChild ( renderLayerManagerObject ( record , index ) ) ) ;
return block ;
@@ -1280,10 +1405,18 @@ function renderLayerManagerObject(record, index) {
object . dataset . objectId = record . id ;
bindLayerManagerExpansion ( object , ` object: ${ record . id } ` ) ;
const visible = ! lmeState . managerHiddenObjectIds . has ( record . id ) ;
object . innerHTML = ` <summary><button type="button" class="layer-drag-handle" aria-label="Trascina oggetto">☰</button><input type="checkbox" ${ visible ? "checked" : "" } aria-label="Mostra oggetto"><span class="layer-manager-title"> ${ escapeHtml ( managedObjectLabel ( record , index ) ) } </span> ${ layerManagerMoveButtons ( "oggetto" ) } <span class="layer-manager-count">› </span></summary><div class="layer-manager-details"></div> ` ;
const renameButton = managedObjectCanRename ( record )
? ` <button type="button" class="layer-rename-button" aria-label="Rinomina oggetto" title="Rinomina">Rinomina</button> `
: "" ;
object . innerHTML = ` <summary><button type="button" class="layer-drag-handle" aria-label="Trascina oggetto">☰</button><input type="checkbox" ${ visible ? "checked" : "" } aria-label="Mostra oggetto"><span class="layer-manager-title"> ${ escapeHtml ( managedObjectLabel ( record , index ) ) } </span> ${ renameButton } ${ layerManagerMoveButtons ( "oggetto" ) } <span class="layer-manager-count">› </span></summary><div class="layer-manager-details"></div> ` ;
const checkbox = object . querySelector ( "input" ) ;
checkbox . addEventListener ( "click" , event => event . stopPropagation ( ) ) ;
checkbox . addEventListener ( "change" , ( ) => setManagedObjectVisible ( record , checkbox . checked , true ) ) ;
object . querySelector ( ".layer-rename-button" ) ? . addEventListener ( "click" , event => {
event . preventDefault ( ) ;
event . stopPropagation ( ) ;
renameManagedObject ( record , index ) ;
} ) ;
object . querySelector ( ".layer-manager-title" ) . addEventListener ( "click" , event => {
event . preventDefault ( ) ;
event . stopPropagation ( ) ;
@@ -1515,9 +1648,75 @@ function highlightManagedObject(record) {
document . querySelectorAll ( ".layer-manager-object" ) . forEach ( row => {
row . classList . toggle ( "layer-manager-object-selected" , row . dataset . objectId === record . id ) ;
} ) ;
const geojson = record . layer . toGeoJSON ? . ( ) ;
if ( geojson ) {
L . geoJSON ( geojson , {
renderManagerHighlight ( [ record ] ) ;
fitLayer ( record . layer ) ;
}
function bindManagedParentHighlight ( row , key , records ) {
const summary = row . querySelector ( ":scope > summary" ) ;
row . dataset . highlightKey = key ;
row . classList . toggle ( "layer-manager-parent-selected" , lmeState . managerHighlightedParentKey === key ) ;
if ( lmeState . managerHighlightedParentKey === key ) {
lmeState . managerHighlightedParentRecords = records ;
}
row . querySelector ( ":scope > summary > .layer-manager-title" ) . addEventListener ( "click" , event => {
event . preventDefault ( ) ;
event . stopPropagation ( ) ;
row . open = true ;
highlightManagedParent ( row , key , records ) ;
} ) ;
summary . addEventListener ( "pointerenter" , ( ) => {
lmeState . managerHoveredParentKey = key ;
lmeState . managerHoveredParentRecords = records ;
row . classList . add ( "layer-manager-parent-highlighted" ) ;
renderManagerHighlight ( records ) ;
} ) ;
summary . addEventListener ( "pointerleave" , ( ) => {
if ( lmeState . managerHoveredParentKey !== key ) {
return ;
}
lmeState . managerHoveredParentKey = null ;
lmeState . managerHoveredParentRecords = null ;
row . classList . remove ( "layer-manager-parent-highlighted" ) ;
renderSelectedManagerHighlight ( ) ;
} ) ;
}
function highlightManagedParent ( row , key , records ) {
if ( lmeState . managerHighlightedParentKey === key ) {
clearManagerHighlight ( ) ;
return ;
}
clearManagerHighlight ( ) ;
lmeState . managerHighlightedParentKey = key ;
lmeState . managerHighlightedParentRecords = records ;
lmeState . managerHighlightedCategoryKey = records [ 0 ] ? . categoryKey || null ;
row . classList . add ( "layer-manager-parent-selected" ) ;
renderManagerHighlight ( records ) ;
}
function renderSelectedManagerHighlight ( ) {
if ( lmeState . managerHighlightedParentRecords ? . length ) {
renderManagerHighlight ( lmeState . managerHighlightedParentRecords ) ;
return ;
}
const selected = lmeState . managerRecords . get ( lmeState . managerHighlightedObjectId ) ;
renderManagerHighlight ( selected ? [ selected ] : [ ] ) ;
}
function renderManagerHighlight ( records ) {
lmeState . managerHighlight ? . clearLayers ( ) ;
const features = records . flatMap ( record => {
const geojson = record . layer ? . toGeoJSON ? . ( ) ;
if ( ! geojson ) {
return [ ] ;
}
return geojson . type === "FeatureCollection" ? geojson . features : [ geojson ] ;
} ) ;
if ( ! features . length ) {
return ;
}
L . geoJSON ( { type : "FeatureCollection" , features } , {
pane : "managerHighlightPane" ,
interactive : false ,
style : { color : "#ff00d4" , weight : 8 , opacity : 1 , fillColor : "#00fff0" , fillOpacity : 0.16 } ,
@@ -1531,17 +1730,25 @@ function highlightManagedObject(record) {
interactive : false
} )
} ) . addTo ( lmeState . managerHighlight ) ;
}
fitLayer ( record . layer ) ;
}
function clearManagerHighlight ( ) {
lmeState . managerHighlight ? . clearLayers ( ) ;
lmeState . managerHighlightedObjectId = null ;
lmeState . managerHighlightedCategoryKey = null ;
lmeState . managerHighlightedParentKey = null ;
lmeState . managerHighlightedParentRecords = null ;
lmeState . managerHoveredParentKey = null ;
lmeState . managerHoveredParentRecords = null ;
document . querySelectorAll ( ".layer-manager-object-selected" ) . forEach ( row => {
row . classList . remove ( "layer-manager-object-selected" ) ;
} ) ;
document . querySelectorAll ( ".layer-manager-parent-highlighted" ) . forEach ( row => {
row . classList . remove ( "layer-manager-parent-highlighted" ) ;
} ) ;
document . querySelectorAll ( ".layer-manager-parent-selected" ) . forEach ( row => {
row . classList . remove ( "layer-manager-parent-selected" ) ;
} ) ;
}
function layerManagerMoveButtons ( label ) {
@@ -2487,6 +2694,7 @@ function captureDisplayOptions() {
selectedParcelsVisible : lmeState . selectedParcelsVisible ,
layerOrder : [ ... lmeState . layerOrder ] ,
layerObjectOrder : { ... lmeState . managerObjectOrder } ,
layerCategoryNames : { ... lmeState . managerCategoryNames } ,
hiddenLayerObjects : [ ... lmeState . managerHiddenObjectIds ] ,
hiddenLayerMeasurementSummaries : [ ... lmeState . managerHiddenMeasurementSummaryIds ] ,
hiddenLayerMeasurementSides : [ ... lmeState . managerHiddenMeasurementSideIds ] ,
@@ -2523,6 +2731,9 @@ function applyProjectDisplayOptions(options) {
if ( options . layerObjectOrder && typeof options . layerObjectOrder === "object" ) {
lmeState . managerObjectOrder = options . layerObjectOrder ;
}
if ( options . layerCategoryNames && typeof options . layerCategoryNames === "object" ) {
lmeState . managerCategoryNames = { ... options . layerCategoryNames } ;
}
if ( Array . isArray ( options . hiddenLayerObjects ) ) {
lmeState . managerHiddenObjectIds = new Set ( options . hiddenLayerObjects ) ;
}
@@ -2609,6 +2820,12 @@ function managedGroupGeoJson(group, categoryKey) {
}
} ) ;
} ) ;
const categoryName = lmeState . managerCategoryNames [ categoryKey ] ;
if ( categoryName ) {
features . forEach ( feature => {
feature . properties = { ... ( feature . properties || { } ) , _lmeCategoryName : categoryName } ;
} ) ;
}
return { type : "FeatureCollection" , features } ;
}
@@ -2619,6 +2836,7 @@ function resetLayerManagerProjectState() {
lmeState . managerHiddenMeasurementSideIds . clear ( ) ;
lmeState . managerHiddenCategories . clear ( ) ;
lmeState . managerObjectOrder = { } ;
lmeState . managerCategoryNames = { } ;
clearManagerHighlight ( ) ;
}
@@ -2641,10 +2859,18 @@ function clearManagedCategoryState(categoryKey) {
}
function bindStoredFeaturePopup ( feature , layer ) {
const properties = feature ? . properties || { } ;
updateStoredFeaturePopup ( layer , feature ? . properties ) ;
}
function updateStoredFeaturePopup ( layer , sourceProperties ) {
const properties = sourceProperties || layer ? . feature ? . properties || { } ;
const label = properties . name || properties . Name || properties . label || properties . LABEL ;
if ( label ) {
layer . bindPopup ( ` <strong> ${ escapeHtml ( label ) } </strong> ` ) ;
return ;
}
if ( typeof layer ? . unbindPopup === "function" ) {
layer . unbindPopup ( ) ;
}
}