diff --git a/js/widgets/genericSelectModal.js b/js/widgets/genericSelectModal.js deleted file mode 100644 index 4f545c2d..00000000 --- a/js/widgets/genericSelectModal.js +++ /dev/null @@ -1,32 +0,0 @@ -function createGenericSelectModal(id, select_id) { - return `` -} - -export {createGenericSelectModal} diff --git a/js/widgets/trackSelectionListModal.js b/js/widgets/trackSelectionListModal.js new file mode 100644 index 00000000..a778e562 --- /dev/null +++ b/js/widgets/trackSelectionListModal.js @@ -0,0 +1,104 @@ +export default function createTrackSelectionListModal({id, label = '', sections, description = '', okHandler}) { + + // Flatten sections to get all tracks. + const tracks = [] + const trackMap = new Map() + const flattenSections = (sections) => { + sections.forEach(section => { + if (section.tracks) { + section.tracks.forEach(track => { + tracks.push(track) + trackMap.set(track._id, track) + }) + } + if (section.children) { + flattenSections(section.children) + } + }) + } + flattenSections(sections) + + // Generate the HTML for the modal + const renderTracks = (tracks) => { + // Generate options for the select element + // Disable options for tracks that are already loaded + const options = tracks.map(track => { + const disabled = track._loaded ? 'disabled' : '' + return `` + }).join('') + + // Return the Bootstrap-styled select widget + return ` +
+ +
+ ` + } + + const html = ` + + ` + + const tempDiv = document.createElement('div') + tempDiv.innerHTML = html.trim() + const modalElement = tempDiv.firstChild + document.body.appendChild(modalElement) + + const modal = new bootstrap.Modal(modalElement, { + backdrop: 'static', + keyboard: false + }) + + let modalAction = null // Variable to track the action + + // Add event listeners to buttons + document.querySelector(`#${id} .btn-secondary`).addEventListener('click', () => { + modalAction = 'ok' + }) + document.querySelector(`#${id} .btn-outline-secondary`).addEventListener('click', () => { + modalAction = 'cancel' + }) + + + // Listen for the modal close event + modalElement.addEventListener('hidden.bs.modal', () => { + if (modalAction === 'ok') { + console.log('Modal closed with OK button') + const selectedOptions = Array.from(modalElement.querySelectorAll('#track-select option:checked')) + const checkedTracks = selectedOptions.map(option => trackMap.get(option.value)) + const uncheckedTracks = [] // There is no way to unselect a track with this widget + + if (okHandler) { + okHandler(checkedTracks, uncheckedTracks) + } else { + console.log('URLs of checked tracks:', checkedTracks) + } + } + + // Clean up resources + modal.dispose() // Dispose of the Bootstrap modal instance + modalElement.remove() // Remove the modal element from the DOM + modalAction = null // Reset the action + }) + + return modal +} diff --git a/js/widgets/trackSelectionModal.js b/js/widgets/trackSelectionModal.js index 06e547ab..cfe1e09a 100644 --- a/js/widgets/trackSelectionModal.js +++ b/js/widgets/trackSelectionModal.js @@ -44,7 +44,7 @@ export default function createTrackSelectionModal({id, label = '', sections, des ${section.tracks ? section.tracks.map((track) => `
- + diff --git a/js/widgets/trackWidgets.js b/js/widgets/trackWidgets.js index a978e7d7..c2f9c8a0 100644 --- a/js/widgets/trackWidgets.js +++ b/js/widgets/trackWidgets.js @@ -18,6 +18,7 @@ import createTrackSelectionModal from './trackSelectionModal.js' import * as Utils from './utils.js' import {initializeDropbox} from "./dropbox.js" import igv from '../../node_modules/igv/dist/igv.esm.js' +import createTrackSelectionListModal from "./trackSelectionListModal.js" const id_prefix = 'genome_specific_' @@ -232,7 +233,7 @@ async function trackMenuGenomeChange(browser, genome) { if (section.tracks) { for (const track of section.tracks) { track._id = trackId(track) - track._checked = loadedIDs.has(track._id) + track._loaded = loadedIDs.has(track._id) } } if (section.children) for (const child of section.children) { @@ -264,7 +265,9 @@ async function trackMenuGenomeChange(browser, genome) { modal.hide() } - const modal = createTrackSelectionModal(config) + const modal = 'hub' === config.type ? + createTrackSelectionModal(config) : + createTrackSelectionListModal(config) modal.show() }) } @@ -276,6 +279,7 @@ function prepRegistryConfig(registry) { if ('custom-data-modal' === registry.type) { const customModalTable = new ModalTable({ + type: registry.type, id: `igv-custom-modal-${Math.random().toString(36).substring(2, 9)}`, title: registry.label, okHandler: trackLoadHandler, @@ -289,6 +293,7 @@ function prepRegistryConfig(registry) { return registry } else { return { + type: registry.type || 'track-selection-modal', id: `_${Math.random().toString(36).substring(2, 9)}`, label: registry.label, description: registry.description, @@ -306,6 +311,7 @@ async function prepHubConfig(hubURL, genomeID) { let descriptionUrl = hub.getDescriptionUrl() const groups = await hub.getGroupedTrackConfigurations(genomeID) return { + type: 'hub', id: `_${Math.random().toString(36).substring(2, 9)}`, label: `${hub.getShortLabel()}`, description: descriptionUrl ? `${hub.getLongLabel()}` : '',