diff --git a/src/c3nav/editor/static/editor/js/editor.js b/src/c3nav/editor/static/editor/js/editor.js
index 69120d08..35ec67c0 100644
--- a/src/c3nav/editor/static/editor/js/editor.js
+++ b/src/c3nav/editor/static/editor/js/editor.js
@@ -2599,6 +2599,8 @@ editor.cloneFloor = {
$('#clone-floor-btn').off('click');
$('#execute-clone-btn').off('click');
$('#cancel-clone-btn').off('click');
+ $('#select-all-btn').off('click');
+ $('#clear-selection-btn').off('click');
// Bind click event to the button that's already in the template
$('#clone-floor-btn').click(editor.cloneFloor.toggleSelectionMode);
@@ -2606,6 +2608,8 @@ editor.cloneFloor = {
// Bind events to the selector elements that are already in the template
$('#execute-clone-btn').click(editor.cloneFloor.executeClone);
$('#cancel-clone-btn').click(editor.cloneFloor.cancelSelection);
+ $('#select-all-btn').click(editor.cloneFloor.selectAllItems);
+ $('#clear-selection-btn').click(editor.cloneFloor.clearSelection);
console.log('Clone floor functionality initialized');
} else {
@@ -2631,24 +2635,34 @@ editor.cloneFloor = {
$('#clone-floor-selector').show();
editor.cloneFloor.updateSelectedCount();
+ // Define supported item types that can be cloned
+ var supportedTypes = ['area', 'obstacle', 'lineobstacle', 'stair', 'ramp', 'hole', 'column', 'poi', 'altitudemarker', 'space', 'building', 'door'];
+
// Add click handlers directly to geometry layers
if (editor._geometries_layer) {
- let layerCount = 0;
+ var layerCount = 0;
+ var supportedCount = 0;
editor._geometries_layer.eachLayer(function(layer) {
if (layer.feature && layer.feature.properties) {
- // Add click handler for selection
- layer.on('click', editor.cloneFloor.onItemClick);
-
- // Make layer visually selectable
- const currentStyle = layer.options || {};
- layer.setStyle(Object.assign({}, currentStyle, {
- cursor: 'pointer',
- opacity: Math.max(currentStyle.opacity || 0, 0.5)
- }));
layerCount++;
+ var itemType = layer.feature.properties.type;
+
+ // Only make supported types selectable
+ if (supportedTypes.indexOf(itemType.toLowerCase()) >= 0) {
+ // Add click handler for selection
+ layer.on('click', editor.cloneFloor.onItemClick);
+
+ // Make layer visually selectable
+ var currentStyle = layer.options || {};
+ layer.setStyle(Object.assign({}, currentStyle, {
+ cursor: 'pointer',
+ opacity: Math.max(currentStyle.opacity || 0, 0.5)
+ }));
+ supportedCount++;
+ }
}
});
- console.log('Clone floor: Made', layerCount, 'geometries selectable');
+ console.log('Clone floor: Made', supportedCount, 'out of', layerCount, 'geometries selectable (supported types only)');
} else {
console.log('Clone floor: No geometries layer found');
}
@@ -2692,8 +2706,8 @@ editor.cloneFloor = {
L.DomEvent.stopPropagation(e);
L.DomEvent.preventDefault(e);
- const layer = e.target;
- const feature = layer.feature;
+ var layer = e.target;
+ var feature = layer.feature;
console.log('Clone floor: Item clicked', feature);
@@ -2702,15 +2716,23 @@ editor.cloneFloor = {
return false;
}
- const itemId = feature.properties.id;
- const itemType = feature.properties.type;
+ var itemId = feature.properties.id;
+ var itemType = feature.properties.type;
console.log('Clone floor: Item ID:', itemId, 'Type:', itemType);
console.log('Clone floor: Full feature properties:', JSON.stringify(feature.properties, null, 2));
+ // Define supported item types that can be cloned
+ var supportedTypes = ['area', 'obstacle', 'lineobstacle', 'stair', 'ramp', 'hole', 'column', 'poi', 'altitudemarker', 'space', 'building', 'door'];
+
+ if (supportedTypes.indexOf(itemType.toLowerCase()) === -1) {
+ console.log('Clone floor: Item type "' + itemType + '" is not supported for cloning. Supported types:', supportedTypes);
+ return false;
+ }
+
// Check if item is already selected
- const existingIndex = editor.cloneFloor.selectedItems.findIndex(
- item => item.item_id === itemId && item.item_type === itemType
+ var existingIndex = editor.cloneFloor.selectedItems.findIndex(
+ function(item) { return item.item_id === itemId && item.item_type === itemType; }
);
if (existingIndex >= 0) {
@@ -2736,6 +2758,56 @@ editor.cloneFloor = {
$('#selected-count').text(editor.cloneFloor.selectedItems.length);
},
+ selectAllItems: function() {
+ if (!editor.cloneFloor.isSelectionMode) {
+ console.log('Clone floor: Select all called but not in selection mode');
+ return;
+ }
+
+ // Clear current selection
+ editor.cloneFloor.selectedItems = [];
+
+ // Define supported item types that can be cloned
+ var supportedTypes = ['area', 'obstacle', 'lineobstacle', 'stair', 'ramp', 'hole', 'column', 'poi', 'altitudemarker', 'space', 'building', 'door'];
+
+ if (editor._geometries_layer) {
+ var selectedCount = 0;
+ editor._geometries_layer.eachLayer(function(layer) {
+ if (layer.feature && layer.feature.properties) {
+ var itemType = layer.feature.properties.type;
+ var itemId = layer.feature.properties.id;
+
+ // Only select supported types
+ if (supportedTypes.indexOf(itemType.toLowerCase()) >= 0) {
+ editor.cloneFloor.selectedItems.push({
+ item_id: itemId,
+ item_type: itemType
+ });
+ selectedCount++;
+ }
+ }
+ });
+ console.log('Clone floor: Selected all', selectedCount, 'supported items');
+ }
+
+ editor.cloneFloor.updateSelectedCount();
+ editor.cloneFloor.updateVisualSelection();
+ },
+
+ clearSelection: function() {
+ if (!editor.cloneFloor.isSelectionMode) {
+ console.log('Clone floor: Clear selection called but not in selection mode');
+ return;
+ }
+
+ // Clear current selection
+ editor.cloneFloor.selectedItems = [];
+ console.log('Clone floor: Cleared all selected items');
+
+ editor.cloneFloor.updateSelectedCount();
+ editor.cloneFloor.updateVisualSelection();
+ },
+
updateVisualSelection: function() {
if (!editor._geometries_layer) return;
@@ -2749,10 +2821,15 @@ editor.cloneFloor = {
// Highlight selected items
editor._geometries_layer.eachLayer(function(layer) {
if (layer.feature && layer.feature.properties) {
- const isSelected = editor.cloneFloor.selectedItems.some(
- item => item.item_id === layer.feature.properties.id &&
- item.item_type === layer.feature.properties.type
- );
+ var isSelected = false;
+ for (var i = 0; i < editor.cloneFloor.selectedItems.length; i++) {
+ var item = editor.cloneFloor.selectedItems[i];
+ if (item.item_id === layer.feature.properties.id &&
+ item.item_type === layer.feature.properties.type) {
+ isSelected = true;
+ break;
+ }
+ }
if (isSelected) {
layer.setStyle({
@@ -2770,8 +2847,8 @@ editor.cloneFloor = {
executeClone: function() {
- const targetLevelId = $('#target-level-select').val();
- const keepSync = $('#keep-sync-checkbox').is(':checked');
+ var targetLevelId = $('#target-level-select').val();
+ var keepSync = $('#keep-sync-checkbox').is(':checked');
if (!targetLevelId) {
alert('Please select a target level');
@@ -2784,7 +2861,7 @@ editor.cloneFloor = {
}
// Get current level ID
- const currentLevelId = editor._level_control.current_level_id;
+ var currentLevelId = editor._level_control.current_level_id;
if (currentLevelId === parseInt(targetLevelId)) {
alert('Source and target levels cannot be the same');
@@ -2795,7 +2872,7 @@ editor.cloneFloor = {
$('#execute-clone-btn').prop('disabled', true).html(' Cloning...');
// Prepare request data
- const requestData = {
+ var requestData = {
source_level_id: currentLevelId,
target_level_id: parseInt(targetLevelId),
items: editor.cloneFloor.selectedItems,
@@ -2828,7 +2905,7 @@ editor.cloneFloor = {
// Log the actual response text for debugging
return response.text().then(function(text) {
console.error('Clone floor: API error response:', text);
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
+ throw new Error('HTTP ' + response.status + ': ' + response.statusText);
});
}
@@ -2840,15 +2917,16 @@ editor.cloneFloor = {
console.log('Clone floor: API response keys:', Object.keys(data));
if (data.success) {
- alert(`Successfully cloned ${data.cloned_items?.length || 0} items: ${data.message}`);
+ var clonedCount = data.cloned_items ? data.cloned_items.length : 0;
+ alert('Successfully cloned ' + clonedCount + ' items: ' + data.message);
editor.cloneFloor.cancelSelection();
} else {
- alert(`Clone failed: ${data.message}`);
+ alert('Clone failed: ' + data.message);
}
})
.catch(function(error) {
console.error('Clone floor: Error details:', error);
- alert(`Clone failed: ${error.message}`);
+ alert('Clone failed: ' + error.message);
})
.finally(function() {
$('#execute-clone-btn').prop('disabled', false).html(' Clone Items');
diff --git a/src/c3nav/editor/templates/editor/level.html b/src/c3nav/editor/templates/editor/level.html
index 91e85297..0082939f 100644
--- a/src/c3nav/editor/templates/editor/level.html
+++ b/src/c3nav/editor/templates/editor/level.html
@@ -51,7 +51,13 @@
-