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

/client/galaxy/scripts/mvc/upload/upload-view.js

https://bitbucket.org/remy_d1/galaxy-central-manageapi
JavaScript | 630 lines | 385 code | 106 blank | 139 comment | 64 complexity | 2b2869c105c9db11451fd504616742a6 MD5 | raw file
Possible License(s): CC-BY-3.0
  1. // dependencies
  2. define(["utils/utils",
  3. "mvc/upload/upload-button",
  4. "mvc/upload/upload-model",
  5. "mvc/upload/upload-row",
  6. "mvc/upload/upload-ftp",
  7. "mvc/ui/ui-popover",
  8. "mvc/ui/ui-modal",
  9. "mvc/ui",
  10. "utils/uploadbox"],
  11. function( Utils,
  12. UploadButton,
  13. UploadModel,
  14. UploadItem,
  15. UploadFtp,
  16. Popover,
  17. Modal
  18. ) {
  19. // galaxy upload
  20. return Backbone.View.extend({
  21. // options
  22. options : {
  23. nginx_upload_path : ''
  24. },
  25. // own modal
  26. modal : null,
  27. // button
  28. ui_button : null,
  29. // jquery uploadbox plugin
  30. uploadbox: null,
  31. // current history
  32. current_history: null,
  33. // current upload size
  34. upload_size: 0,
  35. // extension types
  36. list_extensions :[],
  37. // genomes
  38. list_genomes : [],
  39. // datatype placeholder for auto-detection
  40. auto: {
  41. id : 'auto',
  42. text : 'Auto-detect',
  43. description : 'This system will try to detect the file type automatically. If your file is not detected properly as one of the known formats, it most likely means that it has some format problems (e.g., different number of columns on different rows). You can still coerce the system to set your data to the format you think it should be. You can also upload compressed files, which will automatically be decompressed.'
  44. },
  45. // collection
  46. collection : new UploadModel.Collection(),
  47. // ftp file viewer
  48. ftp : null,
  49. // counter
  50. counter : {
  51. // stats
  52. announce : 0,
  53. success : 0,
  54. error : 0,
  55. running : 0,
  56. // reset stats
  57. reset : function() {
  58. this.announce = this.success = this.error = this.running = 0;
  59. }
  60. },
  61. // initialize
  62. initialize : function(options) {
  63. // link this
  64. var self = this;
  65. // read in options
  66. if (options) {
  67. this.options = _.defaults(options, this.options);
  68. }
  69. // create model
  70. this.ui_button = new UploadButton.Model({
  71. icon : 'fa-upload',
  72. tooltip : 'Download from URL or upload files from disk',
  73. label : 'Load Data',
  74. onclick : function(e) {
  75. if (e) {
  76. // prevent default
  77. e.preventDefault();
  78. // show
  79. self.show()
  80. }
  81. },
  82. onunload : function() {
  83. if (self.counter.running > 0) {
  84. return "Several uploads are still processing.";
  85. }
  86. }
  87. });
  88. // define location
  89. $('#left .unified-panel-header-inner').append((new UploadButton.View(this.ui_button)).$el);
  90. // load extension
  91. var self = this;
  92. Utils.get({
  93. url : galaxy_config.root + "api/datatypes?extension_only=False",
  94. success : function(datatypes) {
  95. for (key in datatypes) {
  96. self.list_extensions.push({
  97. id : datatypes[key].extension,
  98. text : datatypes[key].extension,
  99. description : datatypes[key].description,
  100. description_url : datatypes[key].description_url
  101. });
  102. }
  103. // sort
  104. self.list_extensions.sort(function(a, b) {
  105. return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
  106. });
  107. // add auto field
  108. if (!self.options.datatypes_disable_auto) {
  109. self.list_extensions.unshift(self.auto);
  110. }
  111. }
  112. });
  113. // load genomes
  114. Utils.get({
  115. url : galaxy_config.root + "api/genomes",
  116. success : function(genomes) {
  117. for (key in genomes) {
  118. self.list_genomes.push({
  119. id : genomes[key][1],
  120. text : genomes[key][0]
  121. });
  122. }
  123. // sort
  124. self.list_genomes.sort(function(a, b) {
  125. return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
  126. });
  127. }
  128. });
  129. // events
  130. this.collection.on('remove', function(item) {
  131. self._eventRemove(item);
  132. });
  133. this.collection.on('change:genome', function(item) {
  134. var genome = item.get('genome');
  135. self.collection.each(function(item) {
  136. if (item.get('status') == 'init' && item.get('genome') == '?') {
  137. item.set('genome', genome);
  138. }
  139. });
  140. });
  141. },
  142. //
  143. // event triggered by upload button
  144. //
  145. // show/hide upload frame
  146. show: function () {
  147. // wait for galaxy history panel
  148. var self = this;
  149. if (!Galaxy.currHistoryPanel || !Galaxy.currHistoryPanel.model) {
  150. window.setTimeout(function() { self.show() }, 500)
  151. return;
  152. }
  153. // create modal
  154. if (!this.modal) {
  155. // make modal
  156. var self = this;
  157. this.modal = new Modal.View({
  158. title : 'Download data directly from web or upload files from your disk',
  159. body : this._template('upload-box', 'upload-info'),
  160. buttons : {
  161. 'Choose local file' : function() {self.uploadbox.select()},
  162. 'Choose FTP file' : function() {self._eventFtp()},
  163. 'Paste/Fetch data' : function() {self._eventCreate()},
  164. 'Start' : function() {self._eventStart()},
  165. 'Pause' : function() {self._eventStop()},
  166. 'Reset' : function() {self._eventReset()},
  167. 'Close' : function() {self.modal.hide()},
  168. },
  169. height : '400',
  170. width : '900',
  171. closing_events : true
  172. });
  173. // set element
  174. this.setElement('#upload-box');
  175. // file upload
  176. var self = this;
  177. this.uploadbox = this.$el.uploadbox({
  178. announce : function(index, file, message) { self._eventAnnounce(index, file, message) },
  179. initialize : function(index, file, message) { return self._eventInitialize(index, file, message) },
  180. progress : function(index, file, message) { self._eventProgress(index, file, message) },
  181. success : function(index, file, message) { self._eventSuccess(index, file, message) },
  182. error : function(index, file, message) { self._eventError(index, file, message) },
  183. complete : function() { self._eventComplete() }
  184. });
  185. // add ftp file viewer
  186. var button = this.modal.getButton('Choose FTP file');
  187. this.ftp = new Popover.View({
  188. title : 'FTP files',
  189. container : button
  190. });
  191. }
  192. // show modal
  193. this.modal.show();
  194. // refresh
  195. this._updateUser();
  196. // setup info
  197. this._updateScreen();
  198. },
  199. //
  200. // events triggered by collection
  201. //
  202. // remove item from upload list
  203. _eventRemove : function(item) {
  204. // update status
  205. var status = item.get('status');
  206. // reduce counter
  207. if (status == 'success') {
  208. this.counter.success--;
  209. } else if (status == 'error') {
  210. this.counter.error--;
  211. } else {
  212. this.counter.announce--;
  213. }
  214. // show on screen info
  215. this._updateScreen();
  216. // remove from queue
  217. this.uploadbox.remove(item.id);
  218. },
  219. //
  220. // events triggered by the upload box plugin
  221. //
  222. // a new file has been dropped/selected through the uploadbox plugin
  223. _eventAnnounce : function(index, file, message) {
  224. // update counter
  225. this.counter.announce++;
  226. // update screen
  227. this._updateScreen();
  228. // create view/model
  229. var upload_item = new UploadItem(this, {
  230. id : index,
  231. file_name : file.name,
  232. file_size : file.size,
  233. file_mode : file.mode,
  234. file_path : file.path
  235. });
  236. // add to collection
  237. this.collection.add(upload_item.model);
  238. // add upload item element to table
  239. $(this.el).find('tbody:first').append(upload_item.$el);
  240. // render
  241. upload_item.render();
  242. },
  243. // the uploadbox plugin is initializing the upload for this file
  244. _eventInitialize : function(index, file, message) {
  245. // get element
  246. var it = this.collection.get(index);
  247. // update status
  248. it.set('status', 'running');
  249. // get configuration
  250. var file_name = it.get('file_name');
  251. var file_path = it.get('file_path');
  252. var file_mode = it.get('file_mode');
  253. var extension = it.get('extension');
  254. var genome = it.get('genome');
  255. var url_paste = it.get('url_paste');
  256. var space_to_tabs = it.get('space_to_tabs');
  257. var to_posix_lines = it.get('to_posix_lines');
  258. // validate
  259. if (!url_paste && !(file.size > 0))
  260. return null;
  261. // configure uploadbox
  262. this.uploadbox.configure({url : this.options.nginx_upload_path});
  263. // local files
  264. if (file_mode == 'local') {
  265. this.uploadbox.configure({paramname : 'files_0|file_data'});
  266. } else {
  267. this.uploadbox.configure({paramname : null});
  268. }
  269. // configure tool
  270. tool_input = {};
  271. // new files
  272. if (file_mode == 'new') {
  273. tool_input['files_0|url_paste'] = url_paste;
  274. }
  275. // files from ftp
  276. if (file_mode == 'ftp') {
  277. tool_input['files_0|ftp_files'] = file_path;
  278. }
  279. // add common configuration
  280. tool_input['dbkey'] = genome;
  281. tool_input['file_type'] = extension;
  282. tool_input['files_0|type'] = 'upload_dataset';
  283. tool_input['space_to_tabs'] = space_to_tabs;
  284. tool_input['to_posix_lines'] = to_posix_lines;
  285. // setup data
  286. data = {};
  287. data['history_id'] = this.current_history;
  288. data['tool_id'] = 'upload1';
  289. data['inputs'] = JSON.stringify(tool_input);
  290. // return additional data to be send with file
  291. return data;
  292. },
  293. // progress
  294. _eventProgress : function(index, file, percentage) {
  295. // set progress for row
  296. var it = this.collection.get(index);
  297. it.set('percentage', percentage);
  298. // update ui button
  299. this.ui_button.set('percentage', this._upload_percentage(percentage, file.size));
  300. },
  301. // success
  302. _eventSuccess : function(index, file, message) {
  303. // update status
  304. var it = this.collection.get(index);
  305. it.set('percentage', 100);
  306. it.set('status', 'success');
  307. // file size
  308. var file_size = it.get('file_size');
  309. // update ui button
  310. this.ui_button.set('percentage', this._upload_percentage(100, file_size));
  311. // update completed
  312. this.upload_completed += file_size * 100;
  313. // update counter
  314. this.counter.announce--;
  315. this.counter.success++;
  316. // update on screen info
  317. this._updateScreen();
  318. // update galaxy history
  319. Galaxy.currHistoryPanel.refreshContents();
  320. },
  321. // error
  322. _eventError : function(index, file, message) {
  323. // get element
  324. var it = this.collection.get(index);
  325. // update status
  326. it.set('percentage', 100);
  327. it.set('status', 'error');
  328. it.set('info', message);
  329. // update ui button
  330. this.ui_button.set('percentage', this._upload_percentage(100, file.size));
  331. this.ui_button.set('status', 'danger');
  332. // update completed
  333. this.upload_completed += file.size * 100;
  334. // update counter
  335. this.counter.announce--;
  336. this.counter.error++;
  337. // update on screen info
  338. this._updateScreen();
  339. },
  340. // queue is done
  341. _eventComplete: function() {
  342. // reset queued upload to initial status
  343. this.collection.each(function(item) {
  344. if(item.get('status') == 'queued') {
  345. item.set('status', 'init');
  346. }
  347. });
  348. // update running
  349. this.counter.running = 0;
  350. this._updateScreen();
  351. },
  352. //
  353. // events triggered by this view
  354. //
  355. _eventFtp: function() {
  356. // check if popover is visible
  357. if (!this.ftp.visible) {
  358. // show popover
  359. this.ftp.empty();
  360. this.ftp.append((new UploadFtp(this)).$el);
  361. this.ftp.show();
  362. } else {
  363. // hide popover
  364. this.ftp.hide();
  365. }
  366. },
  367. // create a new file
  368. _eventCreate : function (){
  369. this.uploadbox.add([{
  370. name : 'New File',
  371. size : 0,
  372. mode : 'new'
  373. }]);
  374. },
  375. // start upload process
  376. _eventStart : function() {
  377. // check
  378. if (this.counter.announce == 0 || this.counter.running > 0) {
  379. return;
  380. }
  381. // reset current size
  382. var self = this;
  383. this.upload_size = 0;
  384. this.upload_completed = 0;
  385. // switch icons for new uploads
  386. this.collection.each(function(item) {
  387. if(item.get('status') == 'init') {
  388. item.set('status', 'queued');
  389. self.upload_size += item.get('file_size');
  390. }
  391. });
  392. // reset progress
  393. this.ui_button.set('percentage', 0);
  394. this.ui_button.set('status', 'success');
  395. // update running
  396. this.counter.running = this.counter.announce;
  397. this._updateScreen();
  398. // initiate upload procedure in plugin
  399. this.uploadbox.start();
  400. },
  401. // pause upload process
  402. _eventStop : function() {
  403. // check
  404. if (this.counter.running == 0) {
  405. return;
  406. }
  407. // show upload has paused
  408. this.ui_button.set('status', 'info');
  409. // request pause
  410. this.uploadbox.stop();
  411. // set html content
  412. $('#upload-info').html('Queue will pause after completing the current file...');
  413. },
  414. // remove all
  415. _eventReset : function() {
  416. // make sure queue is not running
  417. if (this.counter.running == 0){
  418. // reset collection
  419. this.collection.reset();
  420. // reset counter
  421. this.counter.reset();
  422. // show on screen info
  423. this._updateScreen();
  424. // remove from queue
  425. this.uploadbox.reset();
  426. // reset button
  427. this.ui_button.set('percentage', 0);
  428. }
  429. },
  430. // update uset
  431. _updateUser: function() {
  432. // backup current history
  433. this.current_user = Galaxy.currUser.get('id');
  434. this.current_history = null;
  435. if (this.current_user) {
  436. this.current_history = Galaxy.currHistoryPanel.model.get('id');
  437. }
  438. },
  439. // set screen
  440. _updateScreen: function () {
  441. /*
  442. update on screen info
  443. */
  444. // check default message
  445. if(this.counter.announce == 0){
  446. if (this.uploadbox.compatible())
  447. message = 'You can Drag & Drop files into this box.';
  448. else
  449. message = 'Unfortunately, your browser does not support multiple file uploads or drag&drop.<br>Some supported browsers are: Firefox 4+, Chrome 7+, IE 10+, Opera 12+ or Safari 6+.'
  450. } else {
  451. if (this.counter.running == 0)
  452. message = 'You added ' + this.counter.announce + ' file(s) to the queue. Add more files or click \'Start\' to proceed.';
  453. else
  454. message = 'Please wait...' + this.counter.announce + ' out of ' + this.counter.running + ' remaining.';
  455. }
  456. // set html content
  457. $('#upload-info').html(message);
  458. /*
  459. update button status
  460. */
  461. // update reset button
  462. if (this.counter.running == 0 && this.counter.announce + this.counter.success + this.counter.error > 0)
  463. this.modal.enableButton('Reset');
  464. else
  465. this.modal.disableButton('Reset');
  466. // update upload button
  467. if (this.counter.running == 0 && this.counter.announce > 0)
  468. this.modal.enableButton('Start');
  469. else
  470. this.modal.disableButton('Start');
  471. // pause upload button
  472. if (this.counter.running > 0)
  473. this.modal.enableButton('Pause');
  474. else
  475. this.modal.disableButton('Pause');
  476. // select upload button
  477. if (this.counter.running == 0){
  478. this.modal.enableButton('Choose local file');
  479. this.modal.enableButton('Choose FTP file');
  480. this.modal.enableButton('Paste/Fetch data');
  481. } else {
  482. this.modal.disableButton('Choose local file');
  483. this.modal.disableButton('Choose FTP file');
  484. this.modal.disableButton('Paste/Fetch data');
  485. }
  486. // ftp button
  487. if (this.current_user && this.options.ftp_upload_dir && this.options.ftp_upload_site) {
  488. this.modal.showButton('Choose FTP file');
  489. } else {
  490. this.modal.hideButton('Choose FTP file');
  491. }
  492. // table visibility
  493. if (this.counter.announce + this.counter.success + this.counter.error > 0) {
  494. $(this.el).find('#upload-table').show();
  495. } else {
  496. $(this.el).find('#upload-table').hide();
  497. }
  498. },
  499. // calculate percentage of all queued uploads
  500. _upload_percentage: function(percentage, size) {
  501. return (this.upload_completed + (percentage * size)) / this.upload_size;
  502. },
  503. // load html template
  504. _template: function(id, idInfo) {
  505. return '<div id="' + id + '" class="upload-box">' +
  506. '<table id="upload-table" class="table table-striped" style="display: none;">' +
  507. '<thead>' +
  508. '<tr>' +
  509. '<th>Name</th>' +
  510. '<th>Size</th>' +
  511. '<th>Type</th>' +
  512. '<th>Genome</th>' +
  513. '<th>Settings</th>' +
  514. '<th>Status</th>' +
  515. '<th></th>' +
  516. '</tr>' +
  517. '</thead>' +
  518. '<tbody></tbody>' +
  519. '</table>' +
  520. '</div>' +
  521. '<h6 id="' + idInfo + '" class="upload-info"></h6>';
  522. }
  523. });
  524. });