diff --git a/js/app.js b/js/app.js
index a25c996..5448647 100644
--- a/js/app.js
+++ b/js/app.js
@@ -48,7 +48,6 @@ import {createSaveImageWidget} from './saveImageWidget.js'
import GtexUtils from "./gtexUtils.js"
import version from "./version.js"
import {createCircularViewResizeModal} from "./circularViewResizeModal.js"
-import {convertToHubURL} from "./ucscUtils.js"
document.addEventListener("DOMContentLoaded", async (event) => await main(document.getElementById('igv-app-container'), igvwebConfig))
@@ -84,7 +83,7 @@ async function main(container, config) {
console.error(str)
const googleWarning = "true" === localStorage.getItem(googleWarningFlag)
//AlertSingleton.present(str)
- if(!googleWarning) {
+ if (!googleWarning) {
localStorage.setItem(googleWarningFlag, "true")
alert(str)
}
@@ -103,14 +102,11 @@ async function main(container, config) {
try {
const lastGenomeId = localStorage.getItem("genomeID")
if (lastGenomeId && lastGenomeId !== igvConfig.genome) {
- if (config.genomes.find(elem => elem.id === lastGenomeId)) {
+ if (config.genomes.find(elem => elem.id === lastGenomeId) ||
+ ((lastGenomeId.startsWith("GCA_") || lastGenomeId.startsWith("GCF_")) && lastGenomeId.length >= 13))
+ {
igvConfig.genome = lastGenomeId
igvConfig.tracks = []
- } else if((lastGenomeId.startsWith("GCA_") || lastGenomeId.startsWith("GCF_")) && lastGenomeId.length >= 13) {
- const hubURL = convertToHubURL(lastGenomeId)
- igvConfig.genome = {
- hubURL: hubURL
- }
}
}
} catch (e) {
@@ -131,7 +127,7 @@ async function main(container, config) {
const urlSet = browser.getTrackURLs()
- for (const { element, url } of urlList) {
+ for (const {element, url} of urlList) {
if (urlSet.has(url)) {
element.setAttribute('disabled', true)
} else {
@@ -242,7 +238,7 @@ async function initializationHelper(browser, container, options) {
const trackLoader = async configurations => {
try {
// Add "searchable" attribute to non-indexed annotation tracks
- for(let c of configurations) {
+ for (let c of configurations) {
}
@@ -301,9 +297,9 @@ async function initializationHelper(browser, container, options) {
document.querySelector('#igv-session-list-divider').style.display = 'none'
}
- createSaveImageWidget({ browser, saveModal: document.getElementById('igv-app-svg-save-modal'), imageType: 'svg' })
+ createSaveImageWidget({browser, saveModal: document.getElementById('igv-app-svg-save-modal'), imageType: 'svg'})
- createSaveImageWidget({ browser, saveModal: document.getElementById('igv-app-png-save-modal'), imageType: 'png' })
+ createSaveImageWidget({browser, saveModal: document.getElementById('igv-app-png-save-modal'), imageType: 'png'})
createShareWidgets(shareWidgetConfigurator(browser, container, options))
@@ -381,7 +377,7 @@ function createSampleInfoMenu(igvMain,
localFileInput.value = ''
- await trackLoadHandler([ { type: 'sampleinfo', url: paths[ 0 ] } ])
+ await trackLoadHandler([{type: 'sampleinfo', url: paths[0]}])
})
// Dropbox
@@ -395,13 +391,14 @@ function createSampleInfoMenu(igvMain,
{
success: dbFiles => {
- const configList = dbFiles.map(( { link } ) => {
- return { type: 'sampleinfo', url: link }
+ const configList = dbFiles.map(({link}) => {
+ return {type: 'sampleinfo', url: link}
})
trackLoadHandler(configList)
},
- cancel: () => {},
+ cancel: () => {
+ },
linkType: "preview",
multiselect: false,
folderselect: false,
@@ -422,8 +419,8 @@ function createSampleInfoMenu(igvMain,
googleDriveButton.addEventListener('click', () => {
const filePickerHandler = async responses => {
- const paths = responses.map(({ url }) => url)
- await trackLoadHandler([ { type: 'sampleinfo', url: paths[ 0 ] } ])
+ const paths = responses.map(({url}) => url)
+ await trackLoadHandler([{type: 'sampleinfo', url: paths[0]}])
}
GooglePicker.createDropdownButtonPicker(false, filePickerHandler)
@@ -433,7 +430,7 @@ function createSampleInfoMenu(igvMain,
// URL
const html =
- `
+ `
@@ -477,17 +474,18 @@ function createSampleInfoMenu(igvMain,
fileLoadManager: new FileLoadManager(),
dataOnly: false,
doURL: true
- };
+ }
const fileLoadWidget = new FileLoadWidget(fileLoadWidgetConfig)
Utils.configureModal(fileLoadWidget, urlModal, async fileLoadWidget => {
const paths = fileLoadWidget.retrievePaths()
- await trackLoadHandler([ { type: 'sampleinfo', url: paths[ 0 ] } ])
+ await trackLoadHandler([{type: 'sampleinfo', url: paths[0]}])
return true
})
}
+
function configureGoogleSignInButton() {
if (true === googleEnabled) {
@@ -505,7 +503,7 @@ function configureGoogleSignInButton() {
if (currentUserProfile) {
const name = currentUserProfile.email || currentUserProfile.name || ''
- signInOutButton.innerText = `Sign Out ${ name }`
+ signInOutButton.innerText = `Sign Out ${name}`
} else {
signInOutButton.innerText = 'Sign In'
}
@@ -656,13 +654,13 @@ async function initializeDropbox() {
}
}
-function guid () {
- return ("0000" + (Math.random() * Math.pow(36, 4) << 0).toString(36)).slice(-4);
+function guid() {
+ return ("0000" + (Math.random() * Math.pow(36, 4) << 0).toString(36)).slice(-4)
}
function isFile(object) {
- if(!object) {
- return false;
+ if (!object) {
+ return false
}
return typeof object !== 'function' &&
(object instanceof File ||
diff --git a/js/genomeWidgets.js b/js/genomeWidgets.js
index de328e4..cc163ef 100644
--- a/js/genomeWidgets.js
+++ b/js/genomeWidgets.js
@@ -27,7 +27,9 @@
import {AlertSingleton, createURLModal,EventBus,FileLoadManager,FileLoadWidget,Utils} from '../node_modules/igv-widgets/dist/igv-widgets.js'
import Globals from "./globals.js";
+const MAX_CUSTOM_GENOMES = 5
let fileLoadWidget;
+let knownGenomeIds = new Set();
function createGenomeWidgets({$igvMain, urlModalId, genomeFileLoad}) {
@@ -59,13 +61,27 @@ function createGenomeWidgets({$igvMain, urlModalId, genomeFileLoad}) {
});
}
+/**
+ * Initialize the genome selection widget with pre-defined and user-defined genomes. Because of the way these
+ * items are added in 'genomeDropdownLayout' they are added in reverse order.
+ *
+ * @param browser
+ * @param genomes
+ * @param $dropdown_menu
+ * @returns {Promise
}
+ */
async function initializeGenomeWidgets(browser, genomes, $dropdown_menu) {
try {
- const genomeMap = await getAppLaunchGenomes(genomes);
+ // Start with predefined genomes. This can return undefined.
+ let genomeMap = await getAppLaunchGenomes(genomes);
- if (genomeMap) {
- genomeDropdownLayout({ browser, genomeMap, $dropdown_menu });
+ // Add user loaded genomes
+ genomeMap = addCustomGenomes(genomeMap || new Map())
+
+ if(genomeMap.size > 0) {
+ genomeDropdownLayout({browser, genomeMap, $dropdown_menu});
+ knownGenomeIds = new Set(genomeMap.keys())
}
} catch (e) {
@@ -78,7 +94,6 @@ async function getAppLaunchGenomes(genomes) {
if (undefined === genomes) {
return undefined;
}
-
if (Array.isArray(genomes)) {
return buildMap(genomes);
} else {
@@ -98,6 +113,20 @@ async function getAppLaunchGenomes(genomes) {
}
}
+function addCustomGenomes(genomeMap) {
+ const customGenomeString = localStorage.getItem("customGenomes")
+ if(customGenomeString) {
+ const customGenomeJson = JSON.parse(customGenomeString)
+ if(customGenomeJson.length > 0) {
+ genomeMap.set('-', '-')
+ for (let json of customGenomeJson.reverse()) {
+ genomeMap.set(json.id, json)
+ }
+ }
+ }
+ return genomeMap
+}
+
function buildMap(arrayOrJson) {
const map = new Map()
@@ -118,27 +147,35 @@ function buildMap(arrayOrJson) {
function genomeDropdownLayout({browser, genomeMap, $dropdown_menu}) {
// discard all buttons preceeding the divider div
+ // TODO -- does this use of find assume there is 1 dropdown-divider? Searching by ID would be more robust.
let $divider = $dropdown_menu.find('.dropdown-divider');
$divider.nextAll().remove();
for (let [ key, value ] of genomeMap) {
- const $button = createButton(value.name);
- $button.insertAfter($divider);
+ if('-' === key) {
+ // Add separator
+ // TODO -- style this,
is a hack
+ $('').insertAfter($divider)
- $button.data('id', key);
+ } else {
+ const $button = createButton(value.name);
+ $button.insertAfter($divider);
- const str = `click.genome-dropdown.${ key }`;
+ $button.data('id', key);
- $button.on(str, async () => {
+ const str = `click.genome-dropdown.${key}`;
- const id = $button.data('id');
+ $button.on(str, async () => {
- if (id !== browser.genome.id) {
- await loadGenome(value);
- }
+ const id = $button.data('id');
- });
+ if (id !== browser.genome.id) {
+ await loadGenome(value);
+ }
+
+ });
+ }
} // for (...)
@@ -159,7 +196,22 @@ async function loadGenome(genomeConfiguration) {
g = await Globals.browser.loadGenome(genomeConfiguration);
if(g.id) {
try {
+
+ // Last loaded genome ID, reloaded automatically on next page load
localStorage.setItem("genomeID", g.id)
+
+ // If this is a previously unknown genome add it to the custom list.
+ if(!knownGenomeIds.has(g.id)) {
+ knownGenomeIds.add(g.id)
+ const customGenomeString = localStorage.getItem("customGenomes")
+ let customGenomeJson = customGenomeString ? JSON.parse(customGenomeString) : []
+ customGenomeJson.unshift(g)
+ if(customGenomeJson.length > MAX_CUSTOM_GENOMES) {
+ customGenomeJson = customGenomeJson.slice(0,MAX_CUSTOM_GENOMES)
+ }
+ localStorage.setItem("customGenomes", JSON.stringify(customGenomeJson))
+ }
+
} catch (e) {
console.error(e)
}
diff --git a/js/ucscUtils.js b/js/ucscUtils.js
deleted file mode 100644
index 2b64dc1..0000000
--- a/js/ucscUtils.js
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-function convertToHubURL(accension) {
- //https://hgdownload.soe.ucsc.edu/hubs/GCF/016/808/095/GCF_016808095.1/
- //https://hgdownload.soe.ucsc.edu/hubs/GCA/028/534/965/GCA_028534965.1/
- if (accension.startsWith("GCF") || accension.startsWith("GCA") && accension.length >= 13) {
- const prefix = accension.substring(0, 3);
- const n1 = accension.substring(4, 7);
- const n2 = accension.substring(7, 10);
- const n3 = accension.substring(10, 13);
- return "https://hgdownload.soe.ucsc.edu/hubs/" + prefix + "/" + n1 + "/" + n2 + "/" + n3 + "/" + accension + "/hub.txt";
- } else {
- return undefined;
- }
-}
-
-export {convertToHubURL}
\ No newline at end of file