PageRenderTime 53ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/static/scripts/mvc/library/library-foldertoolbar-view.js

https://bitbucket.org/afgane/galaxy-central
JavaScript | 1313 lines | 1053 code | 120 blank | 140 comment | 109 complexity | 509ca890d10543c97bd8e7beb7d0b4bb MD5 | raw file
Possible License(s): CC-BY-3.0

Large files files are truncated, but you can click here to view the full file

  1. define([
  2. "galaxy.masthead",
  3. "utils/utils",
  4. "libs/toastr",
  5. "mvc/library/library-model",
  6. "mvc/ui/ui-select"
  7. ],
  8. function( mod_masthead,
  9. mod_utils,
  10. mod_toastr,
  11. mod_library_model,
  12. mod_select
  13. ){
  14. var FolderToolbarView = Backbone.View.extend({
  15. el: '#center',
  16. events: {
  17. 'click #toolbtn_create_folder' : 'createFolderFromModal',
  18. 'click #toolbtn_bulk_import' : 'modalBulkImport',
  19. 'click #include_deleted_datasets_chk' : 'checkIncludeDeleted',
  20. 'click #toolbtn_show_libinfo' : 'showLibInfo',
  21. 'click #toolbtn_bulk_delete' : 'deleteSelectedDatasets',
  22. 'click #page_size_prompt' : 'showPageSizePrompt'
  23. },
  24. defaults: {
  25. 'can_add_library_item' : false,
  26. 'contains_file' : false,
  27. 'chain_call_control' : {
  28. 'total_number' : 0,
  29. 'failed_number' : 0
  30. },
  31. 'disabled_jstree_element' : 'folders'
  32. },
  33. modal : null,
  34. // directory browsing object
  35. jstree: null,
  36. // user's histories
  37. histories : null,
  38. // genome select
  39. select_genome : null,
  40. // extension select
  41. select_extension : null,
  42. // extension types
  43. list_extensions :[],
  44. // datatype placeholder for extension auto-detection
  45. auto: {
  46. id : 'auto',
  47. text : 'Auto-detect',
  48. description : 'This system will try to detect the file type automatically.' +
  49. ' If your file is not detected properly as one of the known formats,' +
  50. ' it most likely means that it has some format problems (e.g., different' +
  51. ' number of columns on different rows). You can still coerce the system' +
  52. ' to set your data to the format you think it should be.' +
  53. ' You can also upload compressed files, which will automatically be decompressed.'
  54. },
  55. // genomes
  56. list_genomes : [],
  57. initialize: function(options){
  58. this.options = _.defaults( options || {}, this.defaults );
  59. this.fetchExtAndGenomes();
  60. this.render();
  61. },
  62. render: function(options){
  63. this.options = _.extend( this.options, options );
  64. var toolbar_template = this.templateToolBar();
  65. var template_defaults = {
  66. id: this.options.id,
  67. is_admin: false,
  68. is_anonym: true,
  69. mutiple_add_dataset_options: false
  70. }
  71. if (Galaxy.currUser){
  72. template_defaults.is_admin = Galaxy.currUser.isAdmin();
  73. template_defaults.is_anonym = Galaxy.currUser.isAnonymous();
  74. if ( Galaxy.config.user_library_import_dir !== null || Galaxy.config.allow_library_path_paste !== false || Galaxy.config.library_import_dir !== null ){
  75. template_defaults.mutiple_add_dataset_options = true;
  76. }
  77. }
  78. this.$el.html(toolbar_template(template_defaults));
  79. },
  80. /**
  81. * Called from FolderListView when needed.
  82. * @param {object} options common options
  83. */
  84. renderPaginator: function( options ){
  85. this.options = _.extend( this.options, options );
  86. var paginator_template = this.templatePaginator();
  87. this.$el.find( '#folder_paginator' ).html( paginator_template({
  88. id: this.options.id,
  89. show_page: parseInt( this.options.show_page ),
  90. page_count: parseInt( this.options.page_count ),
  91. total_items_count: this.options.total_items_count,
  92. items_shown: this.options.items_shown
  93. }));
  94. },
  95. configureElements: function(options){
  96. this.options = _.extend(this.options, options);
  97. if (this.options.can_add_library_item === true){
  98. $('.add-library-items').show();
  99. } else{
  100. $('.add-library-items').hide();
  101. }
  102. if (this.options.contains_file === true){
  103. if (Galaxy.currUser){
  104. if (!Galaxy.currUser.isAnonymous()){
  105. $('.logged-dataset-manipulation').show();
  106. $('.dataset-manipulation').show();
  107. } else {
  108. $('.dataset-manipulation').show();
  109. $('.logged-dataset-manipulation').hide();
  110. }
  111. } else {
  112. $('.logged-dataset-manipulation').hide();
  113. $('.dataset-manipulation').hide();
  114. }
  115. } else {
  116. $('.logged-dataset-manipulation').hide();
  117. $('.dataset-manipulation').hide();
  118. }
  119. this.$el.find('[data-toggle]').tooltip();
  120. },
  121. // shows modal for creating folder
  122. createFolderFromModal: function( event ){
  123. event.preventDefault();
  124. event.stopPropagation();
  125. // create modal
  126. var self = this;
  127. var template = this.templateNewFolderInModal();
  128. this.modal = Galaxy.modal;
  129. this.modal.show({
  130. closing_events : true,
  131. title : 'Create New Folder',
  132. body : template(),
  133. buttons : {
  134. 'Create' : function() {self.create_new_folder_event();},
  135. 'Close' : function() {Galaxy.modal.hide();}
  136. }
  137. });
  138. },
  139. // create the new folder from modal
  140. create_new_folder_event: function(){
  141. var folderDetails = this.serialize_new_folder();
  142. if (this.validate_new_folder(folderDetails)){
  143. var folder = new mod_library_model.FolderAsModel();
  144. url_items = Backbone.history.fragment.split('/');
  145. current_folder_id = url_items[url_items.length-1];
  146. folder.url = folder.urlRoot + '/' + current_folder_id ;
  147. folder.save(folderDetails, {
  148. success: function (folder) {
  149. Galaxy.modal.hide();
  150. mod_toastr.success('Folder created.');
  151. folder.set({'type' : 'folder'});
  152. Galaxy.libraries.folderListView.collection.add(folder);
  153. },
  154. error: function(model, response){
  155. Galaxy.modal.hide();
  156. if (typeof response.responseJSON !== "undefined"){
  157. mod_toastr.error(response.responseJSON.err_msg);
  158. } else {
  159. mod_toastr.error('An error ocurred.');
  160. }
  161. }
  162. });
  163. } else {
  164. mod_toastr.error('Folder\'s name is missing.');
  165. }
  166. return false;
  167. },
  168. // serialize data from the modal
  169. serialize_new_folder : function(){
  170. return {
  171. name: $("input[name='Name']").val(),
  172. description: $("input[name='Description']").val()
  173. };
  174. },
  175. // validate new folder info
  176. validate_new_folder: function(folderDetails){
  177. return folderDetails.name !== '';
  178. },
  179. // show bulk import modal
  180. modalBulkImport : function(){
  181. var checkedValues = $('#folder_table').find(':checked');
  182. if(checkedValues.length === 0){
  183. mod_toastr.info('You must select some datasets first.');
  184. } else {
  185. this.refreshUserHistoriesList(function(that){
  186. var template = that.templateBulkImportInModal();
  187. that.modal = Galaxy.modal;
  188. that.modal.show({
  189. closing_events : true,
  190. title : 'Import into History',
  191. body : template({histories : that.histories.models}),
  192. buttons : {
  193. 'Import' : function() {that.importAllIntoHistory();},
  194. 'Close' : function() {Galaxy.modal.hide();}
  195. }
  196. });
  197. });
  198. }
  199. },
  200. refreshUserHistoriesList: function(callback){
  201. var that = this;
  202. this.histories = new mod_library_model.GalaxyHistories();
  203. this.histories.fetch({
  204. success: function (){
  205. callback(that);
  206. },
  207. error: function(model, response){
  208. if (typeof response.responseJSON !== "undefined"){
  209. mod_toastr.error(response.responseJSON.err_msg);
  210. } else {
  211. mod_toastr.error('An error ocurred.');
  212. }
  213. }
  214. });
  215. },
  216. /**
  217. * Import all selected datasets into history.
  218. */
  219. importAllIntoHistory : function (){
  220. this.modal.disableButton('Import');
  221. var history_id = $("select[name=dataset_import_bulk] option:selected").val();
  222. var history_name = $("select[name=dataset_import_bulk] option:selected").text();
  223. // we can save last used history to pre-select it next time
  224. this.options.last_used_history_id = history_id;
  225. var dataset_ids = [];
  226. $('#folder_table').find(':checked').each(function(){
  227. if (this.parentElement.parentElement.id !== '') {
  228. dataset_ids.push(this.parentElement.parentElement.id);
  229. }
  230. });
  231. // prepare the dataset objects to be imported
  232. var datasets_to_import = [];
  233. for (var i = dataset_ids.length - 1; i >= 0; i--) {
  234. var library_dataset_id = dataset_ids[i];
  235. var historyItem = new mod_library_model.HistoryItem();
  236. historyItem.url = historyItem.urlRoot + history_id + '/contents';
  237. historyItem.content = library_dataset_id;
  238. historyItem.source = 'library';
  239. datasets_to_import.push(historyItem);
  240. }
  241. this.initChainCallControl( { length: datasets_to_import.length, action: 'to_history', history_name: history_name } );
  242. // set the used history as current so user will see the last one
  243. // that he imported into in the history panel on the 'analysis' page
  244. jQuery.getJSON( galaxy_config.root + 'history/set_as_current?id=' + history_id );
  245. this.chainCallImportingIntoHistory( datasets_to_import, history_name );
  246. },
  247. /**
  248. * Update the progress bar in modal window.
  249. */
  250. updateProgress: function(){
  251. this.progress += this.progressStep;
  252. $( '.progress-bar-import' ).width( Math.round( this.progress ) + '%' );
  253. txt_representation = Math.round( this.progress ) + '% Complete';
  254. $( '.completion_span' ).text( txt_representation );
  255. },
  256. /**
  257. * download selected datasets
  258. * @param {str} folder_id id of the current folder
  259. * @param {str} format requested archive format
  260. */
  261. download : function( folder_id, format ){
  262. var dataset_ids = [];
  263. $( '#folder_table' ).find( ':checked' ).each( function(){
  264. if ( this.parentElement.parentElement.id !== '' ) {
  265. dataset_ids.push( this.parentElement.parentElement.id );
  266. }
  267. } );
  268. var url = '/api/libraries/datasets/download/' + format;
  269. var data = { 'ld_ids' : dataset_ids };
  270. this.processDownload( url, data, 'get' );
  271. },
  272. /**
  273. * Create hidden form and submit it through POST
  274. * to initialize the download.
  275. * @param {str} url url to call
  276. * @param {obj} data data to include in the request
  277. * @param {str} method method of the request
  278. */
  279. processDownload: function( url, data, method ){
  280. if ( url && data ){
  281. // data can be string of parameters or array/object
  282. data = typeof data === 'string' ? data : $.param( data );
  283. // split params into form inputs
  284. var inputs = '';
  285. $.each( data.split( '&' ), function(){
  286. var pair = this.split( '=' );
  287. inputs+='<input type="hidden" name="'+ pair[0] +'" value="'+ pair[1] +'" />';
  288. });
  289. // send request
  290. $('<form action="'+ url +'" method="'+ (method||'post') +'">'+inputs+'</form>')
  291. .appendTo( 'body' ).submit().remove();
  292. mod_toastr.info( 'Your download will begin soon.' );
  293. } else {
  294. mod_toastr.error( 'An error occurred.' );
  295. }
  296. },
  297. addFilesFromHistoryModal: function(){
  298. this.refreshUserHistoriesList( function( self ){
  299. self.modal = Galaxy.modal;
  300. var template_modal = self.templateAddFilesFromHistory();
  301. var folder_name = self.options.full_path[self.options.full_path.length - 1][1]
  302. self.modal.show({
  303. closing_events : true,
  304. title : 'Adding datasets from your history to folder ' + folder_name,
  305. body : template_modal({histories: self.histories.models}),
  306. buttons : {
  307. 'Add' : function() {self.addAllDatasetsFromHistory();},
  308. 'Close' : function() {Galaxy.modal.hide();}
  309. },
  310. closing_callback: function(){
  311. Galaxy.libraries.library_router.back();
  312. }
  313. });
  314. // user should always have a history, even anonymous user
  315. if (self.histories.models.length > 0){
  316. self.fetchAndDisplayHistoryContents(self.histories.models[0].id);
  317. $( "#dataset_add_bulk" ).change(function(event) {
  318. self.fetchAndDisplayHistoryContents(event.target.value);
  319. });
  320. } else {
  321. mod_toastr.error( 'An error ocurred.' );
  322. }
  323. });
  324. },
  325. /**
  326. * Create modal for importing from Galaxy path.
  327. * This feature is admin-only.
  328. */
  329. importFilesFromPathModal: function(){
  330. var that = this;
  331. this.modal = Galaxy.modal;
  332. var template_modal = this.templateImportPathModal();
  333. this.modal.show({
  334. closing_events : true,
  335. title : 'Please enter paths to import',
  336. body : template_modal({}),
  337. buttons : {
  338. 'Import' : function() { that.importFromPathsClicked(that); },
  339. 'Close' : function() { Galaxy.modal.hide(); }
  340. },
  341. closing_callback: function(){
  342. // TODO: should not trigger routes outside of the router
  343. Galaxy.libraries.library_router.navigate( 'folders/' + that.id, { trigger: true } );
  344. }
  345. });
  346. this.renderSelectBoxes();
  347. },
  348. /**
  349. * Request all extensions and genomes from Galaxy
  350. * and save them sorted in arrays.
  351. */
  352. fetchExtAndGenomes: function(){
  353. var that = this;
  354. mod_utils.get({
  355. url : galaxy_config.root + "api/datatypes?extension_only=False",
  356. success : function( datatypes ) {
  357. for (key in datatypes) {
  358. that.list_extensions.push({
  359. id : datatypes[key].extension,
  360. text : datatypes[key].extension,
  361. description : datatypes[key].description,
  362. description_url : datatypes[key].description_url
  363. });
  364. }
  365. that.list_extensions.sort(function(a, b) {
  366. return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
  367. });
  368. that.list_extensions.unshift(that.auto);
  369. }
  370. });
  371. mod_utils.get({
  372. url: galaxy_config.root + "api/genomes",
  373. success: function( genomes ) {
  374. for ( key in genomes ) {
  375. that.list_genomes.push({
  376. id : genomes[key][1],
  377. text : genomes[key][0]
  378. });
  379. }
  380. that.list_genomes.sort(function(a, b) {
  381. return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
  382. });
  383. }
  384. });
  385. },
  386. renderSelectBoxes: function(){
  387. // This won't work properly unlesss we already have the data fetched.
  388. // See this.fetchExtAndGenomes()
  389. // TODO switch to common resources:
  390. // https://trello.com/c/dIUE9YPl/1933-ui-common-resources-and-data-into-galaxy-object
  391. var that = this;
  392. this.select_genome = new mod_select.View( {
  393. css: 'library-genome-select',
  394. data: that.list_genomes,
  395. container: Galaxy.modal.$el.find( '#library_genome_select' ),
  396. value: '?'
  397. } );
  398. this.select_extension = new mod_select.View({
  399. css: 'library-extension-select',
  400. data: that.list_extensions,
  401. container: Galaxy.modal.$el.find( '#library_extension_select' ),
  402. value: 'auto'
  403. });
  404. },
  405. /**
  406. * Create modal for importing from given directory
  407. * on Galaxy. Bind jQuery events.
  408. */
  409. importFilesFromGalaxyFolderModal: function( options ){
  410. var that = this;
  411. var template_modal = this.templateBrowserModal();
  412. this.modal = Galaxy.modal;
  413. this.modal.show({
  414. closing_events : true,
  415. title : 'Please select folders or files',
  416. body : template_modal({}),
  417. buttons : {
  418. 'Import' : function() {
  419. that.importFromJstreePath( that, options );
  420. },
  421. 'Close' : function() {
  422. Galaxy.modal.hide();
  423. }
  424. },
  425. closing_callback: function(){
  426. // TODO: should not trigger routes outside of the router
  427. Galaxy.libraries.library_router.navigate('folders/' + that.id, {trigger: true});
  428. }
  429. });
  430. this.renderSelectBoxes();
  431. options.disabled_jstree_element = 'folders';
  432. this.renderJstree( options );
  433. $( 'input[type=radio]' ).change( function( event ){
  434. if (event.target.value ==='jstree-disable-folders') {
  435. options.disabled_jstree_element = 'folders';
  436. that.renderJstree( options );
  437. $('.jstree-folders-message').hide();
  438. $('.jstree-preserve-structure').hide();
  439. $('.jstree-link-files').hide();
  440. $('.jstree-files-message').show();
  441. } else if ( event.target.value ==='jstree-disable-files' ){
  442. $('.jstree-files-message').hide();
  443. $('.jstree-folders-message').show();
  444. $('.jstree-link-files').show();
  445. $('.jstree-preserve-structure').show();
  446. options.disabled_jstree_element = 'files';
  447. that.renderJstree( options );
  448. }
  449. }
  450. );
  451. },
  452. /**
  453. * Fetch the contents of user directory on Galaxy
  454. * and render jstree component based on received
  455. * data.
  456. * @param {[type]} options [description]
  457. */
  458. renderJstree: function( options ){
  459. var that = this;
  460. this.options = _.extend( this.options, options );
  461. var target = options.source || 'userdir';
  462. var disabled_jstree_element = this.options.disabled_jstree_element;
  463. this.jstree = new mod_library_model.Jstree();
  464. this.jstree.url = this.jstree.urlRoot +
  465. '?target=' + target +
  466. '&format=jstree' +
  467. '&disable=' + disabled_jstree_element;
  468. this.jstree.fetch({
  469. success: function(model, response){
  470. // This is to prevent double jquery load. I think. Carl is magician.
  471. define( 'jquery', function(){ return jQuery; });
  472. // Now we need jstree, time to lazy load it.
  473. require([ 'libs/jquery/jstree' ], function(jstree){
  474. $('#jstree_browser').jstree("destroy");
  475. $('#jstree_browser').jstree({
  476. 'core':{
  477. 'data': model
  478. },
  479. 'plugins': ['types', 'checkbox'],
  480. 'types': {
  481. "folder": {
  482. "icon": "jstree-folder"
  483. },
  484. "file": {
  485. "icon": "jstree-file"
  486. }
  487. },
  488. 'checkbox': {
  489. three_state: false
  490. }
  491. });
  492. });
  493. },
  494. error: function(model, response){
  495. if (typeof response.responseJSON !== "undefined"){
  496. mod_toastr.error(response.responseJSON.err_msg);
  497. } else {
  498. mod_toastr.error('An error ocurred.');
  499. }
  500. }
  501. })
  502. },
  503. /**
  504. * Take the paths from the textarea, split it, create
  505. * a request queue and call a function that starts sending
  506. * one by one to be imported on the server.
  507. */
  508. importFromPathsClicked: function(){
  509. var preserve_dirs = this.modal.$el.find('.preserve-checkbox').is(':checked');
  510. var link_data = this.modal.$el.find('.link-checkbox').is(':checked');
  511. var file_type = this.select_extension.value();
  512. var dbkey = this.select_genome.value();
  513. var paths = $('textarea#import_paths').val();
  514. var valid_paths = [];
  515. if (!paths){
  516. mod_toastr.info('Please enter a path relative to Galaxy root.');
  517. } else {
  518. this.modal.disableButton('Import');
  519. paths = paths.split('\n');
  520. for (var i = paths.length - 1; i >= 0; i--) {
  521. trimmed = paths[i].trim();
  522. if (trimmed.length!==0){
  523. valid_paths.push(trimmed);
  524. }
  525. };
  526. this.initChainCallControl( { length: valid_paths.length, action: 'adding_datasets' } );
  527. this.chainCallImportingFolders( { paths: valid_paths,
  528. preserve_dirs: preserve_dirs,
  529. link_data: link_data,
  530. source: 'admin_path',
  531. file_type: file_type,
  532. dbkey: dbkey } );
  533. }
  534. },
  535. /**
  536. * Initialize the control of chaining requests
  537. * in the current modal.
  538. * @param {int} length The number of items in the chain call.
  539. */
  540. initChainCallControl: function( options ){
  541. var template;
  542. switch( options.action ){
  543. case "adding_datasets":
  544. template = this.templateAddingDatasetsProgressBar();
  545. this.modal.$el.find( '.modal-body' ).html( template( { folder_name : this.options.folder_name } ) );
  546. break;
  547. case "deleting_datasets":
  548. template = this.templateDeletingDatasetsProgressBar();
  549. this.modal.$el.find( '.modal-body' ).html( template() );
  550. break;
  551. case "to_history":
  552. template = this.templateImportIntoHistoryProgressBar();
  553. this.modal.$el.find( '.modal-body' ).html( template( { history_name : options.history_name } ) );
  554. break;
  555. default:
  556. console.error( 'Wrong action specified.')
  557. break;
  558. }
  559. // var progress_bar_tmpl = this.templateAddingDatasetsProgressBar();
  560. // this.modal.$el.find( '.modal-body' ).html( progress_bar_tmpl( { folder_name : this.options.folder_name } ) );
  561. this.progress = 0;
  562. this.progressStep = 100 / options.length;
  563. this.options.chain_call_control.total_number = options.length;
  564. this.options.chain_call_control.failed_number = 0;
  565. },
  566. /**
  567. * Take the selected items from the jstree, create a request queue
  568. * and send them one by one to the server for importing into
  569. * the current folder.
  570. *
  571. * jstree.js has to be loaded before
  572. * @see renderJstree
  573. */
  574. importFromJstreePath: function ( that, options ){
  575. var selected_nodes = $( '#jstree_browser' ).jstree().get_selected( true );
  576. var preserve_dirs = this.modal.$el.find( '.preserve-checkbox' ).is( ':checked' );
  577. var link_data = this.modal.$el.find( '.link-checkbox' ).is( ':checked' );
  578. var file_type = this.select_extension.value();
  579. var dbkey = this.select_genome.value();
  580. var selection_type = selected_nodes[0].type;
  581. var paths = [];
  582. if ( selected_nodes.length < 1 ){
  583. mod_toastr.info( 'Please select some items first.' );
  584. } else {
  585. this.modal.disableButton( 'Import' );
  586. for ( var i = selected_nodes.length - 1; i >= 0; i-- ){
  587. if ( selected_nodes[i].li_attr.full_path !== undefined ){
  588. paths.push( selected_nodes[i].li_attr.full_path );
  589. }
  590. }
  591. this.initChainCallControl( { length: paths.length, action: 'adding_datasets' } );
  592. if ( selection_type === 'folder' ){
  593. var full_source = options.source + '_folder';
  594. this.chainCallImportingFolders( { paths: paths,
  595. preserve_dirs: preserve_dirs,
  596. link_data: link_data,
  597. source: full_source,
  598. file_type: file_type,
  599. dbkey: dbkey } );
  600. } else if ( selection_type === 'file' ){
  601. var full_source = options.source + '_file';
  602. this.chainCallImportingUserdirFiles( { paths : paths,
  603. file_type: file_type,
  604. dbkey: dbkey,
  605. source: full_source } );
  606. }
  607. }
  608. },
  609. fetchAndDisplayHistoryContents: function(history_id){
  610. var history_contents = new mod_library_model.HistoryContents({id:history_id});
  611. var self = this;
  612. history_contents.fetch({
  613. success: function(history_contents){
  614. var history_contents_template = self.templateHistoryContents();
  615. self.histories.get(history_id).set({'contents' : history_contents});
  616. self.modal.$el.find('#selected_history_content').html(history_contents_template({history_contents: history_contents.models.reverse()}));
  617. },
  618. error: function(model, response){
  619. if (typeof response.responseJSON !== "undefined"){
  620. mod_toastr.error(response.responseJSON.err_msg);
  621. } else {
  622. mod_toastr.error('An error ocurred.');
  623. }
  624. }
  625. });
  626. },
  627. /**
  628. * Import all selected datasets from history into the current folder.
  629. */
  630. addAllDatasetsFromHistory : function (){
  631. var checked_hdas = this.modal.$el.find( '#selected_history_content' ).find( ':checked' );
  632. var history_dataset_ids = [];
  633. var hdas_to_add = [];
  634. if ( checked_hdas.length < 1 ){
  635. mod_toastr.info( 'You must select some datasets first.' );
  636. } else {
  637. this.modal.disableButton( 'Add' );
  638. checked_hdas.each(function(){
  639. var hid = $( this.parentElement ).data( 'id' );
  640. if ( hid ) {
  641. history_dataset_ids.push( hid );
  642. }
  643. });
  644. for ( var i = history_dataset_ids.length - 1; i >= 0; i-- ) {
  645. history_dataset_id = history_dataset_ids[i];
  646. var folder_item = new mod_library_model.Item();
  647. folder_item.url = '/api/folders/' + this.options.id + '/contents';
  648. folder_item.set( { 'from_hda_id':history_dataset_id } );
  649. hdas_to_add.push( folder_item );
  650. }
  651. this.initChainCallControl( { length: hdas_to_add.length, action: 'adding_datasets' } );
  652. this.chainCallAddingHdas( hdas_to_add );
  653. }
  654. },
  655. /**
  656. * Take array of empty history items and make request for each of them
  657. * to create it on server. Update progress in between calls.
  658. * @param {array} history_item_set array of empty history items
  659. * @param {str} history_name name of the history to import to
  660. */
  661. chainCallImportingIntoHistory: function( history_item_set, history_name ){
  662. var self = this;
  663. var popped_item = history_item_set.pop();
  664. if ( typeof popped_item == "undefined" ) {
  665. if ( this.options.chain_call_control.failed_number === 0 ){
  666. mod_toastr.success( 'Selected datasets imported into history. Click this to start analysing it.', '', { onclick: function() { window.location='/' } } );
  667. } else if ( this.options.chain_call_control.failed_number === this.options.chain_call_control.total_number ){
  668. mod_toastr.error( 'There was an error and no datasets were imported into history.' );
  669. } else if ( this.options.chain_call_control.failed_number < this.options.chain_call_control.total_number ){
  670. mod_toastr.warning( 'Some of the datasets could not be imported into history. Click this to see what was imported.', '', { onclick: function() { window.location='/' } } );
  671. }
  672. Galaxy.modal.hide();
  673. return true;
  674. }
  675. var promise = $.when( popped_item.save( { content: popped_item.content, source: popped_item.source } ) );
  676. promise.done( function(){
  677. self.updateProgress();
  678. self.chainCallImportingIntoHistory( history_item_set, history_name );
  679. } )
  680. .fail( function(){
  681. self.options.chain_call_control.failed_number += 1;
  682. self.updateProgress();
  683. self.chainCallImportingIntoHistory( history_item_set, history_name );
  684. } );
  685. },
  686. /**
  687. * Take the array of paths and createa request for each of them
  688. * calling them in chain. Update the progress bar in between each.
  689. * @param {array} paths paths relative to user folder on Galaxy
  690. */
  691. chainCallImportingUserdirFiles: function( options ){
  692. var that = this;
  693. var popped_item = options.paths.pop();
  694. if ( typeof popped_item === "undefined" ) {
  695. if ( this.options.chain_call_control.failed_number === 0 ){
  696. mod_toastr.success( 'Selected files imported into the current folder' );
  697. Galaxy.modal.hide();
  698. } else {
  699. mod_toastr.error( 'An error occured.' );
  700. }
  701. return true;
  702. }
  703. var promise = $.when( $.post( '/api/libraries/datasets?encoded_folder_id=' + that.id +
  704. '&source=' + options.source +
  705. '&path=' + popped_item +
  706. '&file_type=' + options.file_type +
  707. '&dbkey=' + options.dbkey ) )
  708. promise.done( function( response ){
  709. that.updateProgress();
  710. that.chainCallImportingUserdirFiles( options );
  711. } )
  712. .fail( function(){
  713. that.options.chain_call_control.failed_number += 1;
  714. that.updateProgress();
  715. that.chainCallImportingUserdirFiles( options );
  716. } );
  717. },
  718. /**
  719. * Take the array of paths and createa request for each of them
  720. * calling them in chain. Update the progress bar in between each.
  721. * @param {array} paths paths relative to Galaxy root folder
  722. * @param {boolean} preserve_dirs indicates whether to preserve folder structure
  723. * @param {boolean} link_data copy files to Galaxy or link instead
  724. * @param {str} source string representing what type of folder
  725. * is the source of import
  726. */
  727. chainCallImportingFolders: function( options ){
  728. // TODO need to check which paths to call
  729. var that = this;
  730. var popped_item = options.paths.pop();
  731. if (typeof popped_item == "undefined") {
  732. if (this.options.chain_call_control.failed_number === 0){
  733. mod_toastr.success('Selected folders and their contents imported into the current folder.');
  734. Galaxy.modal.hide();
  735. } else {
  736. // TODO better error report
  737. mod_toastr.error('An error occured.');
  738. }
  739. return true;
  740. }
  741. var promise = $.when( $.post( '/api/libraries/datasets?encoded_folder_id=' + that.id +
  742. '&source=' + options.source +
  743. '&path=' + popped_item +
  744. '&preserve_dirs=' + options.preserve_dirs +
  745. '&link_data=' + options.link_data +
  746. '&file_type=' + options.file_type +
  747. '&dbkey=' + options.dbkey ) )
  748. promise.done(function(response){
  749. that.updateProgress();
  750. that.chainCallImportingFolders( options );
  751. })
  752. .fail(function(){
  753. that.options.chain_call_control.failed_number += 1;
  754. that.updateProgress();
  755. that.chainCallImportingFolders( options );
  756. });
  757. },
  758. /**
  759. * Take the array of hdas and create a request for each.
  760. * Call them in chain and update progress bar in between each.
  761. * @param {array} hdas_set array of empty hda objects
  762. */
  763. chainCallAddingHdas: function( hdas_set ){
  764. var self = this;
  765. this.added_hdas = new mod_library_model.Folder();
  766. var popped_item = hdas_set.pop();
  767. if ( typeof popped_item == "undefined" ) {
  768. if ( this.options.chain_call_control.failed_number === 0 ){
  769. mod_toastr.success( 'Selected datasets from history added to the folder' );
  770. } else if ( this.options.chain_call_control.failed_number === this.options.chain_call_control.total_number ){
  771. mod_toastr.error( 'There was an error and no datasets were added to the folder.' );
  772. } else if ( this.options.chain_call_control.failed_number < this.options.chain_call_control.total_number ){
  773. mod_toastr.warning( 'Some of the datasets could not be added to the folder' );
  774. }
  775. Galaxy.modal.hide();
  776. return this.added_hdas;
  777. }
  778. var promise = $.when( popped_item.save( { from_hda_id: popped_item.get( 'from_hda_id' ) } ) );
  779. promise.done( function( model ){
  780. Galaxy.libraries.folderListView.collection.add( model );
  781. self.updateProgress();
  782. self.chainCallAddingHdas( hdas_set );
  783. })
  784. .fail( function(){
  785. self.options.chain_call_control.failed_number += 1;
  786. self.updateProgress();
  787. self.chainCallAddingHdas( hdas_set );
  788. });
  789. },
  790. /**
  791. * Take the array of lddas, create request for each and
  792. * call them in chain. Update progress bar in between each.
  793. * @param {array} lddas_set array of lddas to delete
  794. */
  795. chainCallDeletingHdas: function( lddas_set ){
  796. var self = this;
  797. this.deleted_lddas = new mod_library_model.Folder();
  798. var popped_item = lddas_set.pop();
  799. if ( typeof popped_item === "undefined" ) {
  800. if ( this.options.chain_call_control.failed_number === 0 ){
  801. mod_toastr.success( 'Selected datasets were deleted.' );
  802. } else if ( this.options.chain_call_control.failed_number === this.options.chain_call_control.total_number ){
  803. mod_toastr.error( 'There was an error and no datasets were deleted. Please make sure you have sufficient permissions.' );
  804. } else if ( this.options.chain_call_control.failed_number < this.options.chain_call_control.total_number ){
  805. mod_toastr.warning( 'Some of the datasets could not be deleted. Please make sure you have sufficient permissions.' );
  806. }
  807. Galaxy.modal.hide();
  808. return this.deleted_lddas;
  809. }
  810. var promise = $.when( popped_item.destroy() );
  811. promise.done( function( dataset ){
  812. Galaxy.libraries.folderListView.collection.remove( popped_item.id );
  813. self.updateProgress();
  814. // add the deleted dataset to collection, triggers rendering
  815. if ( Galaxy.libraries.folderListView.options.include_deleted ){
  816. var updated_dataset = new mod_library_model.Item( dataset );
  817. Galaxy.libraries.folderListView.collection.add( updated_dataset );
  818. }
  819. self.chainCallDeletingHdas( lddas_set );
  820. })
  821. .fail( function(){
  822. self.options.chain_call_control.failed_number += 1;
  823. self.updateProgress();
  824. self.chainCallDeletingHdas( lddas_set );
  825. });
  826. },
  827. /**
  828. * Handles the click on 'show deleted' checkbox
  829. */
  830. checkIncludeDeleted: function(event){
  831. if (event.target.checked){
  832. Galaxy.libraries.folderListView.fetchFolder({include_deleted: true});
  833. } else{
  834. Galaxy.libraries.folderListView.fetchFolder({include_deleted: false});
  835. }
  836. },
  837. /**
  838. * Deletes the selected datasets. Atomic. One by one.
  839. */
  840. deleteSelectedDatasets: function(){
  841. var checkedValues = $('#folder_table').find(':checked');
  842. if(checkedValues.length === 0){
  843. mod_toastr.info('You must select at least one dataset for deletion.');
  844. } else {
  845. var template = this.templateDeletingDatasetsProgressBar();
  846. this.modal = Galaxy.modal;
  847. this.modal.show({
  848. closing_events : true,
  849. title : 'Deleting selected datasets',
  850. body : template({}),
  851. buttons : {
  852. 'Close' : function() {Galaxy.modal.hide();}
  853. }
  854. });
  855. // init the control counters
  856. this.options.chain_call_control.total_number = 0;
  857. this.options.chain_call_control.failed_number = 0;
  858. var dataset_ids = [];
  859. checkedValues.each(function(){
  860. if (this.parentElement.parentElement.id !== '') {
  861. dataset_ids.push(this.parentElement.parentElement.id);
  862. }
  863. });
  864. // init the progress bar
  865. this.progressStep = 100 / dataset_ids.length;
  866. this.progress = 0;
  867. // prepare the dataset items to be added
  868. var lddas_to_delete = [];
  869. for (var i = dataset_ids.length - 1; i >= 0; i--) {
  870. var dataset = new mod_library_model.Item({id:dataset_ids[i]});
  871. lddas_to_delete.push(dataset);
  872. }
  873. this.options.chain_call_control.total_number = dataset_ids.length;
  874. // call the recursive function to call ajax one after each other (request FIFO queue)
  875. this.chainCallDeletingHdas(lddas_to_delete);
  876. }
  877. },
  878. showLibInfo: function(){
  879. var library_id = Galaxy.libraries.folderListView.folderContainer.attributes.metadata.parent_library_id;
  880. var library = null;
  881. var that = this;
  882. if (Galaxy.libraries.libraryListView !== null){
  883. library = Galaxy.libraries.libraryListView.collection.get(library_id);
  884. this.showLibInfoModal(library);
  885. } else {
  886. library = new mod_library_model.Library({id: library_id});
  887. library.fetch({
  888. success: function(){
  889. that.showLibInfoModal(library);
  890. },
  891. error: function(model, response){
  892. if (typeof response.responseJSON !== "undefined"){
  893. mod_toastr.error(response.responseJSON.err_msg);
  894. } else {
  895. mod_toastr.error('An error ocurred.');
  896. }
  897. }
  898. })
  899. }
  900. },
  901. showLibInfoModal: function(library){
  902. var template = this.templateLibInfoInModal();
  903. this.modal = Galaxy.modal;
  904. this.modal.show({
  905. closing_events : true,
  906. title : 'Library Information',
  907. body : template({library:library}),
  908. buttons : {
  909. 'Close' : function() {Galaxy.modal.hide();}
  910. }
  911. });
  912. },
  913. showImportModal: function(options){
  914. switch(options.source){
  915. case "history":
  916. this.addFilesFromHistoryModal();
  917. break;
  918. case "importdir":
  919. this.importFilesFromGalaxyFolderModal( { source: 'importdir' } );
  920. break;
  921. case "path":
  922. this.importFilesFromPathModal();
  923. break;
  924. case "userdir":
  925. this.importFilesFromGalaxyFolderModal( { source: 'userdir' } );
  926. break;
  927. default:
  928. Galaxy.libraries.library_router.back();
  929. mod_toastr.error('Invalid import source.');
  930. break;
  931. }
  932. },
  933. showPageSizePrompt: function(){
  934. var folder_page_size = prompt( 'How many items per page do you want to see?', Galaxy.libraries.preferences.get( 'folder_page_size' ) );
  935. if ( ( folder_page_size != null ) && ( folder_page_size == parseInt( folder_page_size ) ) ) {
  936. Galaxy.libraries.preferences.set( { 'folder_page_size': parseInt( folder_page_size ) } );
  937. Galaxy.libraries.folderListView.render( { id: this.options.id, show_page: 1 } );
  938. }
  939. },
  940. templateToolBar: function(){
  941. tmpl_array = [];
  942. // CONTAINER START
  943. tmpl_array.push('<div class="library_style_container">');
  944. // TOOLBAR START
  945. tmpl_array.push(' <div id="library_toolbar">');
  946. tmpl_array.push(' <span><strong>DATA LIBRARIES</strong></span>');
  947. tmpl_array.push(' <span data-toggle="tooltip" data-placement="top" class="logged-dataset-manipulation" title="Include deleted datasets" style="display:none;"> | <input id="include_deleted_datasets_chk" style="margin: 0;" type="checkbox"> include deleted | </input></span>');
  948. tmpl_array.push(' <button style="display:none;" data-toggle="tooltip" data-placement="top" title="Create New Folder" id="toolbtn_create_folder" class="btn btn-default primary-button add-library-items" type="button"><span class="fa fa-plus"></span> <span class="fa fa-folder"></span></button>');
  949. tmpl_array.push('<% if(mutiple_add_dataset_options) { %>');
  950. tmpl_array.push(' <div class="btn-group add-library-items" style="display:none;">');
  951. tmpl_array.push(' <button title="Add Datasets to Current Folder" id="" type="button" class="primary-button dropdown-toggle" data-toggle="dropdown">');
  952. tmpl_array.push(' <span class="fa fa-plus"></span> <span class="fa fa-file"></span> <span class="caret"></span>');
  953. tmpl_array.push(' </button>');
  954. tmpl_array.push(' <ul class="dropdown-menu" role="menu">');
  955. tmpl_array.push(' <li><a href="#folders/<%= id %>/import/history"> from History</a></li>');
  956. tmpl_array.push('<% if(Galaxy.config.user_library_import_dir !== null) { %>');
  957. tmpl_array.push(' <li><a href="#folders/<%= id %>/import/userdir"> from User Directory</a></li>');
  958. tmpl_array.push('<% } %>');
  959. tmpl_array.push('<% if(Galaxy.config.allow_library_path_paste) { %>');
  960. tmpl_array.push(' <li class="divider"></li>');
  961. tmpl_array.push(' <li class="dropdown-header">Admins only</li>');
  962. tmpl_array.push('<% if(Galaxy.config.library_import_dir !== null) { %>');
  963. tmpl_array.push(' <li><a href="#folders/<%= id %>/import/importdir">from Import Directory</a></li>');
  964. tmpl_array.push('<% } %>');
  965. tmpl_array.push('<% if(Galaxy.config.allow_library_path_paste) { %>');
  966. tmpl_array.push(' <li><a href="#folders/<%= id %>/import/path">from Path</a></li>');
  967. tmpl_array.push('<% } %>');
  968. tmpl_array.push('<% } %>');
  969. tmpl_array.push(' </ul>');
  970. tmpl_array.push(' </div>');
  971. tmpl_array.push('<% } else { %>');
  972. tmpl_array.push(' <button style="display:none;" data-toggle="tooltip" data-placement="top" title="Add Datasets to Current Folder" id="toolbtn_add_files" class="btn btn-default toolbtn_add_files primary-button add-library-items" type="button"><span class="fa fa-plus"></span> <span class="fa fa-file"></span></span></button>');
  973. tmpl_array.push('<% } %>');
  974. tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Import selected datasets into history" id="toolbtn_bulk_import" class="primary-button dataset-manipulation" style="margin-left: 0.5em; display:none;" type="button"><span class="fa fa-book"></span> to History</button>');
  975. tmpl_array.push(' <div id="toolbtn_dl" class="btn-group dataset-manipulation" style="margin-left: 0.5em; display:none; ">');
  976. tmpl_array.push(' <button title="Download selected datasets as archive" id="drop_toggle" type="button" class="primary-button dropdown-toggle" data-toggle="dropdown">');
  977. tmpl_array.push(' <span class="fa fa-download"></span> Download <span class="caret"></span>');
  978. tmpl_array.push(' </button>');
  979. tmpl_array.push(' <ul class="dropdown-menu" role="menu">');
  980. tmpl_array.push(' <li><a href="#/folders/<%= id %>/download/tgz">.tar.gz</a></li>');
  981. tmpl_array.push(' <li><a href="#/folders/<%= id %>/download/tbz">.tar.bz</a></li>');
  982. tmpl_array.push(' <li><a href="#/folders/<%= id %>/download/zip">.zip</a></li>');
  983. tmpl_array.push(' </ul>');
  984. tmpl_array.push(' </div>');
  985. tmpl_array.push(' <button data-toggle="tooltip" data-placement="top" title="Mark selected datasets deleted" id="toolbtn_bulk_delete" class="primary-button logged-dataset-manipulation" style="margin-left: 0.5em; display:none; " type="button"><span class="fa fa-times"></span> Delete</button>');
  986. tmpl_array.push(' <button data-id="<%- id %>" data-toggle="tooltip" data-placement="top" title="Show library information" id="toolbtn_show_libinfo" class="primary-button" style="margin-left: 0.5em;" type="button"><span class="fa fa-info-circle"></span> Library Info</button>');
  987. tmpl_array.push(' <span class="help-button" data-toggle="tooltip" data-placement="top" title="Visit Libraries Wiki"><a href="https://wiki.galaxyproject.org/DataLibraries/screen/FolderContents" target="_blank"><button class="primary-button" type="button"><span class="fa fa-question-circle"></span> Help</button></a></span>');
  988. tmpl_array.push(' <span id="folder_paginator" class="library-paginator">');
  989. // paginator will append here
  990. tmpl_array.push(' </span>');
  991. tmpl_array.push(' </div>');
  992. // TOOLBAR END
  993. tmpl_array.push(' <div id="folder_items_element">');
  994. tmpl_array.push(' </div>');
  995. tmpl_array.push('</div>');
  996. // CONTAINER END
  997. return _.template(tmpl_array.join(''));
  998. },
  999. templateLibInfoInModal: function(){
  1000. tmpl_array = [];
  1001. tmpl_array.push('<div id="lif_info_modal">');
  1002. tmpl_array.push('<h2>Library name:</h2>');
  1003. tmpl_array.push('<p><%- library.get("name") %></p>');
  1004. tmpl_array.push('<h3>Library description:</h3>');
  1005. tmpl_array.push('<p><%- library.get("description") %></p>');
  1006. tmpl_array.push('<h3>Library synopsis:</h3>');
  1007. tmpl_array.push('<p><%- library.get("synopsis") %></p>');
  1008. tmpl_array.push('</div>');
  1009. return _.template(tmpl_array.join(''));
  1010. },
  1011. templateNewFolderInModal: function(){
  1012. tmpl_array = [];
  1013. tmpl_array.push('<div id="new_folder_modal">');
  1014. tmpl_array.push('<form>');
  1015. tmpl_array.push('<input type="text" name="Name" value="" placeholder="Name">');
  1016. tmpl_array.push('<input type="text" name="Description" value="" placeholder="Description">');
  1017. tmpl_array.push('</form>');
  1018. tmpl_array.push('</div>');
  1019. return _.template(tmpl_array.join(''));
  1020. },
  1021. templateBulkImportInModal : function(){
  1022. var tmpl_array = [];
  1023. tmpl_array.push('<span id="history_modal_combo_bulk" style="width:90%; margin-left: 1em; margin-right: 1em; ">');
  1024. tmpl_array.push('Select history: ');
  1025. tmpl_array.push('<select id="dataset_import_bulk" name="dataset_import_bulk" style="width:50%; margin-bottom: 1em; "> ');
  1026. tmpl_array.push(' <% _.each(histories, function(history) { %>'); //history select box
  1027. tmpl_array.push(' <option value="<%= _.escape(history.get("id")) %>"><%= _.escape(history.get("name")) %></option>');
  1028. tmpl_array.push(' <% }); %>');
  1029. tmpl_array.push('</select>');
  1030. tmpl_array.push('</span>');
  1031. return _.template(tmpl_array.join(''));
  1032. },
  1033. templateImportIntoHistoryProgressBar : function (){
  1034. var tmpl_array = [];
  1035. tmpl_array.push('<div class="import_text">');
  1036. tmpl_array.push('Importing selected datasets to history <b><%= _.escape(history_name) %></b>');
  1037. tmpl_array.push('</div>');
  1038. tmpl_array.push('<div class="progress">');
  1039. tmpl_array.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');
  1040. tmpl_array.push(' <span class="completion_span">0% Complete</span>');
  1041. tmpl_array.push(' </div>');
  1042. tmpl_array.push('</div>');
  1043. tmpl_array.push('');
  1044. return _.template(tmpl_array.join(''));
  1045. },
  1046. templateAddingDatasetsProgressBar: function (){
  1047. var tmpl_array = [];
  1048. tmpl_array.push('<div class="import_text">');
  1049. tmpl_array.push('Adding selected datasets to library folder <b><%= _.escape(folder_name) %></b>');
  1050. tmpl_array.push('</div>');
  1051. tmpl_array.push('<div class="progress">');
  1052. tmpl_array.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');
  1053. tmpl_array.push(' <span class="completion_span">0% Complete</span>');
  1054. tmpl_array.push(' </div>');
  1055. tmpl_array.push('</div>');
  1056. tmpl_array.push('');
  1057. return _.template(tmpl_array.join(''));
  1058. },
  1059. templateDeletingDatasetsProgressBar: function (){
  1060. var tmpl_array = [];
  1061. tmpl_array.push('<div class="import_text">');
  1062. tmpl_array.push('</div>');
  1063. tmpl_array.push('<div class="progress">');
  1064. tmpl_array.push(' <div class="progress-bar progress-bar-import" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 00%;">');
  1065. tmpl_array.push(' <span class="completion_span">0% Complete</span>');
  1066. tmpl_array.push(' </div>');
  1067. tmpl_array.push('</div>');
  1068. tmpl_array.push('');
  1069. return _.template(tmpl_array.join(''));
  1070. },
  1071. templateBrowserModal: function(){
  1072. var tmpl_array = [];
  1073. tmpl_array.push('<div id="file_browser_modal">');
  1074. tmpl_array.push('<div class="alert alert-info jstree-files-message">All files you select will be imported into the current folder.</div>');
  1075. tmpl_array.push('<div class="alert alert-info jstree-folders-message" style="display:none;">All files within the selected folders and their subfolders will be imported into the current folder.</div>');
  1076. tmpl_array.push('<div style="margin-bottom:1em;">');
  1077. tmpl_array.push('<label class="radio-inline">');
  1078. tmpl_array.push(' <input title="Switch to selecting files" type="radio" name="jstree-radio" value="jstree-disable-folders" checked="checked"> Files');
  1079. tmpl_array.push('</label>');
  1080. tmpl_array.push('<label class="radio-inline">');
  1081. tmpl_array.push(' <input title="Switch to selecting folders" type="radio" name="jstree-radio" value="jstree-disable-files"> Folders');
  1082. tmpl_array.push('</label>');
  1083. tmpl_array.push('</div>');
  1084. tmpl_array.push('<div style="margin-bottom:1em;">');
  1085. tmpl_array.push('<label class="checkbox-inline jstree-preserve-structure" style="display:none;">');
  1086. tmpl_array.push(' <input class="preserve-checkbox" type="checkbox" value="preserve_directory_structure">');
  1087. tmpl_array.push('Preserve directory structure');
  1088. tmpl_array.push(' </label>');
  1089. tmpl_array.push('<label class="checkbox-inline jstree-link-files" style="display:none;">');
  1090. tmpl_array.push(' <input class="link-checkbox" type="checkbox" value="link_files">');
  1091. tmpl_array.push('Link files instead of copying');
  1092. tmpl_array.push(' </label>');
  1093. tmpl_array.push('</div>');
  1094. tmpl_array.push('<div id="jstree_browser">');
  1095. tmpl_array.push('</div>');
  1096. tmpl_array.push('<hr />');
  1097. tmpl_array.push('<p>You can set extension type and genome for all imported datasets at once:</p>');
  1098. tmpl_array.push('<div>');
  1099. tmpl_array.push('Type: <span id="library_extension_select" class="library-extension-select" />');
  1100. tmpl_array.push(' Genome: <span id="library_genome_select" class="library-genome-select" />');
  1101. tmpl_array.push('</div>');
  1102. tmpl_array.push('</div>');
  1103. return _.template(tmpl_array.join(''));
  1104. },
  1105. templateImportPathModal: function(){
  1106. var tmpl_ar

Large files files are truncated, but you can click here to view the full file