diff --git a/src/api/dashboard/static/js/ui/indicators-panel-new.js b/src/api/dashboard/static/js/ui/indicators-panel-new.js
index 6f42c52..91c552d 100644
--- a/src/api/dashboard/static/js/ui/indicators-panel-new.js
+++ b/src/api/dashboard/static/js/ui/indicators-panel-new.js
@@ -6,7 +6,7 @@ let configuringId = null;
let searchQuery = '';
let selectedCategory = 'all';
let nextInstanceId = 1;
-let eventListenersSet = false;
+let listenersAttached = false; // Single flag to track if any listeners are attached
// Chart pane management
let indicatorPanes = new Map();
@@ -35,14 +35,6 @@ const CATEGORY_MAP = {
const DEFAULT_COLORS = ['#2962ff', '#26a69a', '#ef5350', '#ff9800', '#9c27b0', '#00bcd4', '#ffeb3b', '#e91e63'];
const LINE_TYPES = ['solid', 'dotted', 'dashed'];
-// Initialize
-export function initIndicatorPanel() {
- console.log('[IndicatorPanel] Initializing...');
- renderIndicatorPanel();
- setupEventListeners();
- console.log('[IndicatorPanel] Initialized');
-}
-
function getDefaultColor(index) {
return DEFAULT_COLORS[index % DEFAULT_COLORS.length];
}
@@ -92,6 +84,12 @@ function groupPlotsByColor(plots) {
return Object.values(groups);
}
+export function initIndicatorPanel() {
+ console.log('[IndicatorPanel] Initializing...');
+ renderIndicatorPanel();
+ console.log('[IndicatorPanel] Initialized');
+}
+
export function getActiveIndicators() {
return activeIndicators;
}
@@ -136,7 +134,7 @@ export function renderIndicatorPanel() {
value="${searchQuery}"
autocomplete="off"
>
- ${searchQuery ? `` : ''}
+ ${searchQuery ? `` : ''}
@@ -167,7 +165,7 @@ export function renderIndicatorPanel() {
${activeIndicators.length} Active
- ${activeIndicators.length > 0 ? `` : ''}
+ ${activeIndicators.length > 0 ? `` : ''}
${activeIndicators.slice().reverse().map(ind => renderActiveIndicator(ind)).join('')}
@@ -188,9 +186,9 @@ export function renderIndicatorPanel() {
`;
// Only setup event listeners once
- if (!eventListenersSet) {
+ if (!listenersAttached) {
setupEventListeners();
- eventListenersSet = true;
+ listenersAttached = true;
}
}
@@ -220,19 +218,24 @@ function renderActiveIndicator(indicator) {
const meta = getIndicatorMeta(indicator);
const label = getIndicatorLabel(indicator);
const isFavorite = userPresets.favorites?.includes(indicator.type) || false;
-
+ const showPresets = meta.name && function() {
+ const hasPresets = typeof getPresetsForIndicator === 'function' ? getPresetsForIndicator(meta.name) : [];
+ if (!hasPresets || hasPresets.length === 0) return '';
+ return `
+
+
`;
+ }();
+
return `
-
+
⋮⋮
-
@@ -250,10 +253,10 @@ function renderActiveIndicator(indicator) {
}
function renderPresetIndicatorIndicator(meta, indicator) {
- const hasPresets = getPresetsForIndicator(meta.name);
+ const hasPresets = typeof getPresetsForIndicator === 'function' ? getPresetsForIndicator(meta.name) : [];
if (!hasPresets || hasPresets.length === 0) return '';
- return `
💾`;
+ return `
💾`;
}
function renderIndicatorConfig(indicator, meta) {
@@ -271,7 +274,7 @@ function renderIndicatorConfig(indicator, meta) {
@@ -280,19 +283,18 @@ function renderIndicatorConfig(indicator, meta) {
-
-
+
${indicator.params._lineWidth || 2}
-
${meta?.inputs && meta.inputs.length > 0 ? `
Parameters
@@ -300,61 +302,53 @@ function renderIndicatorConfig(indicator, meta) {
`).join('')}
` : ''}
-
Presets
- + Save Preset
+ + Save Preset
- ${renderIndicatorPresets(indicator, meta)}
+ ${typeof renderIndicatorPresets === 'function' ? renderIndicatorPresets(indicator, meta) : ''}
-
- Reset to Defaults
- Remove
+ Reset to Defaults
+ Remove
`;
}
function renderIndicatorPresets(indicator, meta) {
- const presets = getPresetsForIndicator(meta.name);
- const instance = new IR[indicator.type]({ type: indicator.type, params: indicator.params, name: indicator.name });
- const metadata = instance.getMetadata();
+ const presets = typeof getPresetsForIndicator === 'function' ? getPresetsForIndicator(meta.name) : [];
return presets.length > 0 ? `
- ${presets.map(preset => {
- // Match values against current settings
- const isApplied = metadata.inputs.every(input =>
- preset.values[input.name] === indicator.params[input.name]
+ ${presets.map(p => {
+ const isApplied = meta.inputs.every(input =>
+ (indicator.params[input.name] === (preset.values?.[input.name] ?? input.default))
);
return `
- ${preset.name}
- ×
+ ${preset.name}
+ ×
`;
}).join('')}
@@ -364,44 +358,59 @@ function renderIndicatorPresets(indicator, meta) {
// Event listeners
function setupEventListeners() {
- // Event delegation for dynamically created elements
const container = document.getElementById('indicatorPanel');
- if (container) {
- // Add button
- container.addEventListener('click', (e) => {
- const addBtn = e.target.closest('.indicator-btn.add');
- if (addBtn) {
- const type = addBtn.dataset.type;
- if (type && window.addIndicator) {
- window.addIndicator(type);
- }
+ if (!container) return;
+
+ console.log('[IndicatorPanel] Setting up event listeners...');
+
+ // Single event delegation handler for add button
+ container.addEventListener('click', (e) => {
+ const addBtn = e.target.closest('.indicator-btn.add');
+ if (addBtn) {
+ e.stopPropagation();
+ const type = addBtn.dataset.type;
+ if (type && window.addIndicator) {
+ console.log('[IndicatorPanel] Adding indicator:', type);
+ window.addIndicator(type);
}
- });
+ return;
+ }
- // Config / expand button
- container.addEventListener('click', (e) => {
- const expandBtn = e.target.closest('.indicator-btn.expand');
- if (expandBtn) {
- const id = expandBtn.dataset.id;
- if (id && window.toggleIndicatorExpand) {
- window.toggleIndicatorExpand(id);
- }
+ // Expand/collapse button
+ const expandBtn = e.target.closest('.indicator-btn.expand');
+ if (expandBtn) {
+ e.stopPropagation();
+ const id = expandBtn.dataset.id;
+ if (id && window.toggleIndicatorExpand) {
+ window.toggleIndicatorExpand(id);
}
- });
+ return;
+ }
// Remove button
- container.addEventListener('click', (e) => {
- const removeBtn = e.target.closest('.indicator-btn.remove');
- if (removeBtn) {
- const id = removeBtn.dataset.id;
- if (id && window.removeIndicatorById) {
- window.removeIndicatorById(id);
- }
+ const removeBtn = e.target.closest('.indicator-btn.remove');
+ if (removeBtn) {
+ e.stopPropagation();
+ const id = removeBtn.dataset.id;
+ if (id && window.removeIndicatorById) {
+ window.removeIndicatorById(id);
}
- });
- }
+ return;
+ }
+
+ // Favorite button
+ const favoriteBtn = e.target.closest('.indicator-btn.favorite');
+ if (favoriteBtn) {
+ e.stopPropagation();
+ const type = favoriteBtn.dataset.type;
+ if (type && window.toggleFavorite) {
+ window.toggleFavorite(type);
+ }
+ return;
+ }
+ });
- // Search
+ // Search input
const searchInput = document.getElementById('indicatorSearch');
if (searchInput) {
searchInput.addEventListener('input', (e) => {
@@ -410,6 +419,15 @@ function setupEventListeners() {
});
}
+ // Search clear button
+ const searchClear = container.querySelector('.search-clear');
+ if (searchClear) {
+ searchClear.addEventListener('click', (e) => {
+ searchQuery = '';
+ renderIndicatorPanel();
+ });
+ }
+
// Category tabs
document.querySelectorAll('.category-tab').forEach(tab => {
tab.addEventListener('click', (e) => {
@@ -417,6 +435,16 @@ function setupEventListeners() {
renderIndicatorPanel();
});
});
+
+ // Clear all button
+ const clearAllBtn = container.querySelector('.clear-all');
+ if (clearAllBtn) {
+ clearAllBtn.addEventListener('click', () => {
+ window.clearAllIndicators();
+ });
+ }
+
+ console.log('[IndicatorPanel] Event listeners setup complete');
}
// Actions
@@ -434,7 +462,7 @@ window.clearAllIndicators = function() {
activeIndicators = [];
configuringId = null;
renderIndicatorPanel();
-drawIndicatorsOnChart();
+ drawIndicatorsOnChart();
};
function addIndicator(type) {
@@ -469,7 +497,7 @@ function addIndicator(type) {
configuringId = id;
renderIndicatorPanel();
drawIndicatorsOnChart();
-};
+}
window.toggleIndicatorExpand = function(id) {
configuringId = configuringId === id ? null : id;
@@ -492,7 +520,10 @@ window.toggleIndicatorVisibility = function(id) {
};
window.toggleFavorite = function(type) {
- const favorites = userPresets.favorites || [];
+ if (!userPresets) userPresets = {};
+ if (!userPresets.favorites) userPresets.favorites = [];
+
+ const favorites = userPresets.favorites;
const idx = favorites.indexOf(type);
if (idx >= 0) {
@@ -536,9 +567,9 @@ window.resetIndicator = function(id) {
if (!IndicatorClass) return;
const instance = new IndicatorClass({ type: indicator.type, params: {}, name: indicator.name });
- const metadata = instance.getMetadata();
+ const meta = instance.getMetadata();
- metadata.inputs.forEach(input => {
+ meta.inputs.forEach(input => {
indicator.params[input.name] = input.default;
});
@@ -546,7 +577,12 @@ window.resetIndicator = function(id) {
drawIndicatorsOnChart();
};
-function removeIndicatorById(id) {
+window.removeIndicator = function() {
+ if (!configuringId) return;
+ removeIndicatorById(configuringId);
+};
+
+window.removeIndicatorById = function(id) {
const idx = activeIndicators.findIndex(a => a.id === id);
if (idx < 0) return;
@@ -562,7 +598,7 @@ function removeIndicatorById(id) {
renderIndicatorPanel();
drawIndicatorsOnChart();
-}
+};
function removeIndicatorByIndex(index) {
if (index < 0 || index >= activeIndicators.length) return;
@@ -571,8 +607,8 @@ function removeIndicatorByIndex(index) {
// Presets
function getPresetsForIndicator(indicatorName) {
- const allPresets = Object.values(userPresets).flat().filter(p => typeof p === 'object' && p.name);
- return allPresets.filter(p => p.indicatorName === indicatorName);
+ if (!userPresets || !userPresets.presets) return [];
+ return userPresets.presets.filter(p => p.indicatorName === indicatorName);
}
window.savePreset = function(id) {
@@ -608,7 +644,7 @@ window.savePreset = function(id) {
};
window.applyPreset = function(id, presetId) {
- const allPresets = Object.values(userPresets).flat().filter(p => typeof p === 'object' && p.id);
+ const allPresets = (userPresets?.presets || []).filter(p => typeof p === 'object' && p.id);
const preset = allPresets.find(p => p.id === presetId);
if (!preset) return;
@@ -626,7 +662,7 @@ window.applyPreset = function(id, presetId) {
window.deletePreset = function(presetId) {
if (!confirm('Delete this preset?')) return;
- if (userPresets.presets) {
+ if (userPresets?.presets) {
userPresets.presets = userPresets.presets.filter(p => p.id !== presetId);
saveUserPresets();
renderIndicatorPanel();
@@ -821,6 +857,12 @@ export function drawIndicatorsOnChart() {
});
}
+// Export functions for module access
+export const addIndicator = addIndicator;
+export const removeIndicatorById = removeIndicatorById;
+export const removeIndicatorByIndexFunction = removeIndicatorByIndex;
+const removeIndicatorByIndex = removeIndicatorByIndex;
+
// Legacy compatibility functions
window.renderIndicatorList = renderIndicatorPanel;
window.toggleIndicator = addIndicator;
@@ -832,20 +874,15 @@ window.showIndicatorConfig = function(id) {
window.applyIndicatorConfig = function() {
// No-op - config is applied immediately
};
-window.removeIndicator = function() {
- if (!configuringId) return;
- removeIndicatorById(configuringId);
-};
// Assign to window for backward compatibility
-window.toggleIndicator = addIndicator;
window.addIndicator = addIndicator;
+window.toggleIndicator = addIndicator;
window.removeIndicatorById = removeIndicatorById;
-window.removeIndicatorByIndex = function(index) {
+window.removeIndicatorByIndex = removeIndicatorByIndexWindow;
+const removeIndicatorByIndexWindow = function(index) {
if (index < 0 || index >= activeIndicators.length) return;
removeIndicatorById(activeIndicators[index].id);
};
-window.drawIndicatorsOnChart = drawIndicatorsOnChart;
-
-// Export functions for module imports
-export { addIndicator, removeIndicatorById, removeIndicatorByIndex };
\ No newline at end of file
+window.removeIndicatorByIndex = removeIndicatorByIndexWindow;
+window.drawIndicatorsOnChart = drawIndicatorsOnChart;
\ No newline at end of file