diff --git a/src/JBrowse/Browser.js b/src/JBrowse/Browser.js index 0cfb926c14..09991971ae 100644 --- a/src/JBrowse/Browser.js +++ b/src/JBrowse/Browser.js @@ -1257,7 +1257,7 @@ openFastaElectron: function() { window.location = window.location.href.split('?')[0] + "?data=" + Util.replacePath( dir ); } catch(e) { alert(e); } } - else if( confs[0].store.blob ) { + else if( confs[0].store.type == 'JBrowse/Store/SeqFeature/TwoBit' ) { var f2bit = Util.replacePath( confs[0].store.blob.url ); var refseqs = new TwoBit({'browser': this, 'urlTemplate': f2bit }); @@ -1333,76 +1333,49 @@ openFastaElectron: function() { }, openFasta: function() { - var thisB=this; this.fastaFileDialog = this.fastaFileDialog || new FastaFileDialog({browser: this}); - var replaceBrowser = function (newBrowserGenerator) { - thisB.teardown() - newBrowserGenerator() - } - this.fastaFileDialog.show ({ - openCallback: dojo.hitch(this, function(results) { - var confs = results.trackConfs || []; - function loadNewRefSeq(refSeqs, tracks) { - replaceBrowser(function() { - var newBrowser = new thisB.constructor({ - refSeqs: { data: refSeqs }, - refSeqOrder: results.refSeqOrder - }); - newBrowser.afterMilestone('completely initialized', function() { - array.forEach( tracks, function( conf ) { - var storeConf = conf.store; - if( storeConf && typeof storeConf == 'object' ) { - delete conf.store; - storeConf.name = 'refseqs'; // important to make it the refseq store - conf.store = this.addStoreConfig( storeConf.name, storeConf ); - } - }, newBrowser); - newBrowser.publish( '/jbrowse/v1/v/tracks/new', tracks ); - }); - }); - } - if( confs.length ) { - if( confs[0].store.fasta && confs[0].store.fai ) { - new IndexedFasta({ - browser: this, - fai: confs[0].store.fai, - fasta: confs[0].store.fasta - }) - .getRefSeqs( - function(refSeqs) { loadNewRefSeq( refSeqs, confs ); }, - function(error) { alert('Error getting refSeq: '+error); } - ); - } - else if( confs[0].store.blob ) { - new TwoBit({ - browser: this, - blob: confs[0].store.blob - }) - .getRefSeqs( - function(refSeqs) { loadNewRefSeq( refSeqs, confs ); }, - function(error) { alert('Error getting refSeq: '+error); } - ); - } - else if( confs[0].store.fasta ) { - if( confs[0].store.fasta.size > 100000000 ) { - if(!confirm('Warning: you are opening a non-indexed fasta larger than 100MB. It is recommended to load a fasta (.fa) and the fasta index (.fai) to provide speedier loading. Do you wish to continue anyways?')) { - return; - } - } - new UnindexedFasta({ - browser: this, - fasta: confs[0].store.fasta - }) - .getRefSeqs( - function(refSeqs) { loadNewRefSeq( refSeqs, confs ); }, - function(error) { alert('Error getting refSeq: '+error); } - ); - } + openCallback: results => { + return new Promise((resolve,reject) => { + const trackConfigs = results.trackConfs || [] + const [conf] = trackConfigs + if (!conf) return reject('no track configs') + const storeConf = conf.store + if (!storeConf) return reject('no store config') + + dojo.global.require( [storeConf.type], (storeClass) => { + if( /\/Unindexed/i.test(storeConf.type) && storeConf.fasta && storeConf.fasta.size > 100000000 ) { + alert('Unindexed file too large. You must have an index file (.fai) for sequence files larger than 100 MB.') + return reject('sequence file too large') + } - } - }) + const store = new storeClass( + Object.assign({ browser: this }, storeConf) + ) + .getRefSeqs( + refSeqs => { + this.teardown() + var newBrowser = new this.constructor({ + refSeqs: { data: refSeqs }, + refSeqOrder: results.refSeqOrder + }) + newBrowser.afterMilestone('completely initialized', () => { + storeConf.name = 'refseqs' // important to make it the refseq store + newBrowser.addStoreConfig( storeConf.name, storeConf ) + conf.store = 'refseqs' + newBrowser.publish( '/jbrowse/v1/v/tracks/new', [conf] ) + }) + resolve() + }, + error => { + this.fatalError('Error getting refSeq: '+error) + reject(error) + } + ); + }) + }) + } }); }, @@ -2092,9 +2065,12 @@ loadConfig: function () { this._addTrackConfigs( tracks ); // coerce some config keys to boolean - dojo.forEach( ['show_tracklist','show_nav','show_overview','show_menu', 'show_fullviewlink', 'show_tracklabels', 'update_browser_title'], function(v) { - this.config[v] = this._coerceBoolean( this.config[v] ); - },this); + [ + 'show_tracklist','show_nav','show_overview','show_menu', + 'show_fullviewlink', 'show_tracklabels', 'update_browser_title' + ].forEach( v => { + this.config[v] = Util.coerceBoolean( this.config[v] ); + }) // set empty tracks array if we have none if( ! this.config.tracks ) @@ -2204,34 +2180,6 @@ _configDefaults: function() { }; }, -/** - * Coerce a value of unknown type to a boolean, treating string 'true' - * and 'false' as the values they indicate, and string numbers as - * numbers. - * @private - */ -_coerceBoolean: function(val) { - if( typeof val == 'string' ) { - val = val.toLowerCase(); - if( val == 'true' ) { - return true; - } - else if( val == 'false' ) - return false; - else - return parseInt(val); - } - else if( typeof val == 'boolean' ) { - return val; - } - else if( typeof val == 'number' ) { - return !!val; - } - else { - return true; - } -}, - /** * @param refSeqs {Array} array of refseq records to add to the browser */ diff --git a/src/JBrowse/Util.js b/src/JBrowse/Util.js index 5ef8c79f69..b09fe8ede6 100644 --- a/src/JBrowse/Util.js +++ b/src/JBrowse/Util.js @@ -515,6 +515,35 @@ Util = { } return r; }, + + /** + * Coerce a value of unknown type to a boolean, treating string 'true' + * and 'false' as the values they indicate, and string numbers as + * numbers. + * @private + */ + coerceBoolean: function(val) { + if( typeof val == 'string' ) { + val = val.toLowerCase(); + if( val == 'true' ) { + return true; + } + else if( val == 'false' ) + return false; + else + return parseInt(val); + } + else if( typeof val == 'boolean' ) { + return val; + } + else if( typeof val == 'number' ) { + return !!val; + } + else { + return true; + } + }, + }; return Util; diff --git a/src/JBrowse/View/FastaFileDialog.js b/src/JBrowse/View/FastaFileDialog.js index e4e9f1016a..0a76b7463c 100644 --- a/src/JBrowse/View/FastaFileDialog.js +++ b/src/JBrowse/View/FastaFileDialog.js @@ -70,19 +70,22 @@ return declare( FileDialog, { }) .placeAt( actionBar ); - new Button({ iconClass: 'dijitIconFolderOpen', - label: 'Open', - onClick: dojo.hitch( this, function() { - openCallback && openCallback({ - trackConfs: this.trackList.getTrackConfigurations(), - refSeqOrder: this.refSeqOrderChoice[0].checked ? "alphabetic descending" : - this.refSeqOrderChoice[1].checked ? "length descending" : - undefined - }); - this.dialog.hide(); - }) - }) - .placeAt( actionBar ); + new Button({ + iconClass: 'dijitIconFolderOpen', + label: 'Open', + onClick: () => { + if (openCallback) { + openCallback({ + trackConfs: this.trackList.getTrackConfigurations(), + refSeqOrder: this.refSeqOrderChoice[0].checked ? "alphabetic descending" : + this.refSeqOrderChoice[1].checked ? "length descending" : + undefined + }) + .then( () => this.dialog.hide(), err => { console.error(err) } ) + } + } + }) + .placeAt( actionBar ); return { domNode: actionBar }; } diff --git a/src/JBrowse/View/FileDialog/TrackList/IndexedFASTADriver.js b/src/JBrowse/View/FileDialog/TrackList/IndexedFASTADriver.js index bf53d052a4..37c13d9915 100644 --- a/src/JBrowse/View/FileDialog/TrackList/IndexedFASTADriver.js +++ b/src/JBrowse/View/FileDialog/TrackList/IndexedFASTADriver.js @@ -1,11 +1,12 @@ define([ 'dojo/_base/declare', - './_IndexedFileDriver' + './_OptionallyIndexedFileDriver' ], - function( declare, IndexedFileDriver ) { -return declare( IndexedFileDriver, { + function( declare, OptionallyIndexedFileDriver ) { +return declare( OptionallyIndexedFileDriver, { name: 'FASTA', storeType: 'JBrowse/Store/SeqFeature/IndexedFasta', + unindexedStoreType: 'JBrowse/Store/SeqFeature/UnindexedFasta', fileExtension: 'fasta', fileConfKey: 'fasta', @@ -14,21 +15,5 @@ return declare( IndexedFileDriver, { indexExtension: 'fai', indexConfKey: 'fai', indexUrlConfKey: 'faiUrlTemplate', - - - tryResource: function(configs, resource) { - this.inherited(arguments); - }, - finalizeConfiguration: function(configs) { - this.inherited(arguments); - for(var i in configs) { - var config = configs[i]; - if( !config.fai && !config.blob ) { - // if no fai, change to UnindexedFasta - config.type = "JBrowse/Store/SeqFeature/UnindexedFasta"; - } - } - } }); - }); diff --git a/src/JBrowse/View/FileDialog/TrackList/_OptionallyIndexedFileDriver.js b/src/JBrowse/View/FileDialog/TrackList/_OptionallyIndexedFileDriver.js new file mode 100644 index 0000000000..159a788ebb --- /dev/null +++ b/src/JBrowse/View/FileDialog/TrackList/_OptionallyIndexedFileDriver.js @@ -0,0 +1,62 @@ +define([ + 'dojo/_base/declare', + 'JBrowse/Util', + './_IndexedFileDriver', + ], + function( declare, Util, _IndexedFileDriver ) { +return declare( _IndexedFileDriver, { + + // try to merge any singleton file and index stores. currently can only do this if there is one of each + finalizeConfiguration: function( configs ) { + var singletonIndexes = {}; + var singletonIndexCount = 0; + var singletonFiles = {}; + var singletonFileCount = 0; + for( var n in configs ) { + var conf = configs[n]; + if( conf.type === this.storeType ) { + if( (conf[this.indexConfKey] || conf[this.indexUrlConfKey]) && ! ( conf[this.fileConfKey] || conf[this.fileUrlConfKey] ) ) { + // singleton Index + singletonIndexCount++; + singletonIndexes[n] = conf; + } + else if(( conf[this.fileConfKey] || conf[this.fileUrlConfKey] ) && ! ( conf[this.indexConfKey] || conf[this.indexUrlConfKey]) ) { + // singleton File + singletonFileCount++; + singletonFiles[n] = conf; + } + } + } + + // if we have a single File and single Index left at the end, + // stick them together and we'll see what happens + if( singletonFileCount == 1 && singletonIndexCount == 1 ) { + for( var indexName in singletonIndexes ) { + for( var fileName in singletonFiles ) { + if( singletonIndexes[indexName][this.indexUrlConfKey] ) + singletonFiles[fileName][this.indexUrlConfKey] = singletonIndexes[indexName][this.indexUrlConfKey]; + if( singletonIndexes[indexName][this.indexConfKey] ) + singletonFiles[fileName][this.indexConfKey] = singletonIndexes[indexName][this.indexConfKey]; + + delete configs[indexName]; + } + } + } + + // delete any remaining singleton Indexes, since they don't have + // a hope of working + for( var indexName in singletonIndexes ) { + delete configs[indexName]; + } + + // make any remaining singleton data files be unindexed stores + for( var fileName in singletonFiles ) { + configs[fileName].type = this.unindexedStoreType; + } + }, + + confIsValid: function( conf ) { + return (conf[this.fileConfKey] || conf[this.fileUrlConfKey]); + } +}); +}); diff --git a/src/JBrowse/View/TrackConfigEditor.js b/src/JBrowse/View/TrackConfigEditor.js index 6dc4a85a7c..d479c38763 100644 --- a/src/JBrowse/View/TrackConfigEditor.js +++ b/src/JBrowse/View/TrackConfigEditor.js @@ -108,6 +108,7 @@ return declare( null, { realChange(); previousText = textArea.value; } + // TODO: do not renew this timeout if the dialog is destroyed window.setTimeout( checkForChange, checkFrequency ); } }; @@ -160,4 +161,4 @@ return declare( null, { } }); -}); \ No newline at end of file +});