@gmod/jbrowse
Version:
JBrowse - client-side genome browser
280 lines (248 loc) • 10.7 kB
JavaScript
define( [
'dojo/_base/declare',
'dojo/_base/array',
'dojo/aspect',
'dojo/on',
'dijit/focus',
'dijit/form/Button',
'dijit/form/RadioButton',
'dojo/dom-construct',
'dijit/Dialog',
'dojox/form/Uploader',
'./FileDialog/TrackList/BAMDriver',
'./FileDialog/TrackList/CRAMDriver',
'./FileDialog/TrackList/BigWigDriver',
'./FileDialog/TrackList/GFF3Driver',
'./FileDialog/TrackList/GTFDriver',
'./FileDialog/TrackList/VCFTabixDriver',
'./FileDialog/TrackList/VCFTribbleDriver',
'./FileDialog/TrackList/BEDTabixDriver',
'./FileDialog/TrackList/GFF3TabixDriver',
'./FileDialog/TrackList/BEDDriver',
'./FileDialog/TrackList/BigBedDriver',
'./FileDialog/ResourceList',
'./FileDialog/TrackList',
'JBrowse/Util'
],
function(
declare,
array,
aspect,
on,
dijitFocus,
Button,
RadioButton,
dom,
Dialog,
Uploaded,
BAMDriver,
CRAMDriver,
BigWigDriver,
GFF3Driver,
GTFDriver,
VCFTabixDriver,
VCFTribbleDriver,
BEDTabixDriver,
GFF3TabixDriver,
BEDDriver,
BigBedDriver,
ResourceList,
TrackList,
Util
) {
return declare( null, {
constructor: function( args ) {
this.browser = args.browser;
this.config = dojo.clone( args.config || {} );
this.browserSupports = {
dnd: 'draggable' in document.createElement('span')
};
this._fileTypeDrivers = [
new BAMDriver(),
new CRAMDriver(),
new BigWigDriver(),
new GFF3Driver(),
new GTFDriver(),
new VCFTabixDriver(),
new VCFTribbleDriver(),
new BEDTabixDriver(),
new GFF3TabixDriver(),
new BEDDriver(),
new BigBedDriver()
];
},
addFileTypeDriver: function( d ) {
this._fileTypeDrivers.unshift( d );
},
getFileTypeDrivers: function() {
return this._fileTypeDrivers.slice();
},
_makeActionBar: function( openCallback, cancelCallback ) {
var actionBar = dom.create(
'div', {
className: 'dijitDialogPaneActionBar'
});
var disChoices = this.trackDispositionChoice = [
new RadioButton({ id: 'openImmediately',
value: 'openImmediately',
checked: true
}),
new RadioButton({ id: 'addToTrackList',
value: 'addToTrackList'
})
];
var aux = dom.create('div',{className:'aux'},actionBar);
disChoices[0].placeAt(aux);
dom.create('label', { "for": 'openImmediately', innerHTML: 'Open immediately' }, aux ),
disChoices[1].placeAt(aux);
dom.create('label', { "for": 'addToTrackList', innerHTML: 'Add to tracks' }, aux );
new Button({ iconClass: 'dijitIconDelete', label: 'Cancel',
onClick: dojo.hitch( this, function() {
cancelCallback && cancelCallback();
this.dialog.hide();
})
})
.placeAt( actionBar );
new Button({ iconClass: 'dijitIconFolderOpen',
label: 'Open',
onClick: dojo.hitch( this, function() {
openCallback && openCallback({
trackConfs: this.trackList.getTrackConfigurations(),
trackDisposition: this.trackDispositionChoice[0].checked ? this.trackDispositionChoice[0].value :
this.trackDispositionChoice[1].checked ? this.trackDispositionChoice[1].value :
undefined
});
this.dialog.hide();
})
})
.placeAt( actionBar );
return { domNode: actionBar };
},
show: function( args ) {
var dialog = this.dialog = new Dialog(
{ title: "Open files", className: 'fileDialog' }
);
var localFilesControl = this._makeLocalFilesControl();
var remoteURLsControl = this._makeRemoteURLsControl();
var resourceListControl = this._makeResourceListControl();
var trackListControl = this._makeTrackListControl();
var actionBar = this._makeActionBar( args.openCallback, args.cancelCallback );
// connect the local files control to the resource list
dojo.connect( localFilesControl.uploader, 'onChange', function() {
if(Util.isElectron()) {
const arr = [...localFilesControl.uploader._files].map((file) => Util.replacePath(file.path));
resourceListControl.addURLs(arr);
} else {
resourceListControl.addLocalFiles( localFilesControl.uploader._files );
}
});
// connect the remote URLs control to the resource list
dojo.connect( remoteURLsControl, 'onChange', function( urls ) {
resourceListControl.clearURLs();
resourceListControl.addURLs( urls );
});
// connect the resource list to the track list
dojo.connect( resourceListControl, 'onChange', function( resources ) {
trackListControl.update( resources );
});
var div = function( attr, children ) {
var d = dom.create('div', attr );
array.forEach( children, dojo.hitch( d, 'appendChild' ));
return d;
};
var content = [
dom.create( 'div', { className: 'intro', innerHTML: args.introMsg||'Add any combination of data files and URLs, and JBrowse will automatically suggest tracks to display their contents.' } ),
div( { className: 'resourceControls' },
[ localFilesControl.domNode, remoteURLsControl.domNode ]
),
resourceListControl.domNode,
trackListControl.domNode,
actionBar.domNode
];
dialog.set( 'content', content );
dialog.show();
aspect.after( dialog, 'hide', dojo.hitch( this, function() {
dijitFocus.curNode && dijitFocus.curNode.blur();
setTimeout( function() { dialog.destroyRecursive(); }, 500 );
}));
},
_makeLocalFilesControl: function() {
var container = dom.create('div', { className: 'localFilesControl' });
dom.create('h3', { innerHTML: 'Local files' }, container );
var dragArea = dom.create('div', { className: 'dragArea' }, container );
var fileBox;
fileBox = new dojox.form.Uploader({
multiple: true
});
fileBox.placeAt( dragArea );
if( this.browserSupports.dnd ) {
// let the uploader process any files dragged into the dialog
fileBox.addDropTarget( this.dialog.domNode );
// add a message saying you can drag files in
dom.create(
'div', {
className: 'dragMessage',
innerHTML: 'Select or drag files here.'
}, dragArea
);
}
// little elements used to show pipeline-like connections between the controls
dom.create( 'div', { className: 'connector', innerHTML: ' '}, container );
return { domNode: container, uploader: fileBox };
},
_makeRemoteURLsControl: function() {
var container = dom.create('div', { className: 'remoteURLsControl' });
// make the input elements
dom.create('h3', { innerHTML: 'Remote URLs - <smaller>one per line</smaller>' }, container );
// the onChange here will be connected to by the other parts
// of the dialog to propagate changes to the text in the box
var self = { domNode: container,
onChange: function(urls) {
//console.log('urls changed');
}
};
self.input = dom.create( 'textarea', {
className: 'urlInput',
placeHolder: "http://paste.urls.here/example.bam",
cols: 25,
rows: 5,
spellcheck: false
}, container );
// set up the handlers to propagate changes
var realChange = function() {
var text = dojo.trim( self.input.value );
var urls = text.length ? text.split( /\s+/ ) : [];
self.onChange( urls );
};
// watch the input text for changes. just do it every 900ms
// because there are many ways that text can get changed (like
// pasting), not all of which fire the same events. not using
// the onchange event, because that doesn't fire until the
// textarea loses focus.
var previousText = '';
var checkFrequency = 900;
var checkForChange = function() {
// compare with all whitespace changed to commas so that
// we are insensitive to changes in whitespace
if( self.input.value.replace(/\s+/g,',') != previousText ) {
realChange();
previousText = self.input.value.replace(/\s+/g,',');
}
window.setTimeout( checkForChange, checkFrequency );
};
window.setTimeout( checkForChange, checkFrequency );
// little elements used to show pipeline-like connections between the controls
dom.create( 'div', { className: 'connector', innerHTML: ' '}, container );
return self;
},
_makeResourceListControl: function () {
var rl = new ResourceList({ dialog: this });
return rl;
},
_makeTrackListControl: function() {
var tl = new TrackList({ browser: this.browser, fileDialog: this });
this.trackList = tl;
return tl;
}
});
});