PageRenderTime 39ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/static/scripts/mvc/upload/upload-row.js

https://bitbucket.org/remy_d1/galaxy-central-manageapi
JavaScript | 406 lines | 257 code | 63 blank | 86 comment | 32 complexity | 7276ccffdc5f6104011f62ae17a5b839 MD5 | raw file
Possible License(s): CC-BY-3.0
  1. // dependencies
  2. define(['utils/utils',
  3. 'mvc/upload/upload-model',
  4. 'mvc/upload/upload-settings',
  5. 'mvc/ui/ui-popover',
  6. 'mvc/ui/ui-select'],
  7. function( Utils,
  8. UploadModel,
  9. UploadSettings,
  10. Popover,
  11. Select
  12. ) {
  13. // item view
  14. return Backbone.View.extend({
  15. // options
  16. options: {
  17. padding : 8
  18. },
  19. // states
  20. status_classes : {
  21. init : 'upload-icon-button fa fa-trash-o',
  22. queued : 'upload-icon fa fa-spinner fa-spin',
  23. running : 'upload-icon fa fa-spinner fa-spin',
  24. success : 'upload-icon-button fa fa-check',
  25. error : 'upload-icon-button fa fa-exclamation-triangle'
  26. },
  27. // handle for settings popover
  28. settings: null,
  29. // genome selector
  30. select_genome : null,
  31. // extension selector
  32. select_extension : null,
  33. // render
  34. initialize: function(app, options) {
  35. // link app
  36. this.app = app;
  37. // link this
  38. var self = this;
  39. // create model
  40. this.model = new UploadModel.Model(options);
  41. // add upload item
  42. this.setElement(this._template(options));
  43. // link item
  44. var it = this.$el;
  45. // append popup to settings icon
  46. this.settings = new Popover.View({
  47. title : 'Upload configuration',
  48. container : it.find('#settings'),
  49. placement : 'bottom'
  50. });
  51. // select genomes
  52. this.select_genome = new Select.View({
  53. css: 'genome',
  54. onchange : function() {
  55. self.model.set('genome', self.select_genome.value());
  56. },
  57. data: self.app.list_genomes,
  58. container: it.find('#genome'),
  59. value: self.model.get('genome')
  60. });
  61. // initialize genome
  62. this.model.set('genome', self.select_genome.value());
  63. // select extension
  64. this.select_extension = new Select.View({
  65. css: 'extension',
  66. onchange : function() {
  67. self.model.set('extension', self.select_extension.value());
  68. },
  69. data: self.app.list_extensions,
  70. container: it.find('#extension'),
  71. value: self.model.get('extension')
  72. });
  73. // initialize extension
  74. this.model.set('extension', self.select_extension.value());
  75. //
  76. // ui events
  77. //
  78. // handle click event
  79. it.find('#symbol').on('click', function() { self._removeRow(); });
  80. // handle extension info popover
  81. it.find('#extension-info').on('click' , function(e) { self._showExtensionInfo(); })
  82. .on('mousedown', function(e) { e.preventDefault(); });
  83. // handle settings popover
  84. it.find('#settings').on('click' , function(e) { self._showSettings(); })
  85. .on('mousedown', function(e) { e.preventDefault(); });
  86. // handle text editing event
  87. it.find('#text-content').on('keyup', function(e) {
  88. self.model.set('url_paste', $(e.target).val());
  89. self.model.set('file_size', $(e.target).val().length);
  90. });
  91. // handle space to tabs button
  92. it.find('#space_to_tabs').on('change', function(e) {
  93. self.model.set('space_to_tabs', $(e.target).prop('checked'));
  94. });
  95. //
  96. // model events
  97. //
  98. this.model.on('change:percentage', function() {
  99. self._refreshPercentage();
  100. });
  101. this.model.on('change:status', function() {
  102. self._refreshStatus();
  103. });
  104. this.model.on('change:info', function() {
  105. self._refreshInfo();
  106. });
  107. this.model.on('change:genome', function() {
  108. self._refreshGenome();
  109. });
  110. this.model.on('change:file_size', function() {
  111. self._refreshFileSize();
  112. });
  113. this.model.on('remove', function() {
  114. self.remove();
  115. });
  116. this.app.collection.on('reset', function() {
  117. self.remove();
  118. });
  119. },
  120. // render
  121. render: function() {
  122. // read model
  123. var file_name = this.model.get('file_name');
  124. var file_size = this.model.get('file_size');
  125. var file_mode = this.model.get('file_mode');
  126. // link item
  127. var it = this.$el;
  128. // update title
  129. it.find('#title').html(file_name);
  130. // update info
  131. it.find('#size').html(Utils.bytesToString (file_size));
  132. // remove mode class
  133. it.find('#mode').removeClass()
  134. .addClass('mode');
  135. // activate text field if file is new
  136. if (file_mode == 'new') {
  137. // get text component
  138. var text = it.find('#text');
  139. // get padding
  140. var padding = this.options.padding;
  141. // get dimensions
  142. var width = it.width() - 2 * padding;
  143. var height = it.height() - padding;
  144. // set dimensions
  145. text.css('width', width + 'px');
  146. text.css('top', height + 'px');
  147. it.height(height + text.height() + 2 * padding);
  148. // show text field
  149. text.show();
  150. // update icon
  151. it.find('#mode').addClass('fa fa-pencil');
  152. }
  153. // file from local disk
  154. if (file_mode == 'local') {
  155. // update icon
  156. it.find('#mode').addClass('fa fa-laptop');
  157. }
  158. // file from ftp
  159. if (file_mode == 'ftp') {
  160. // update icon
  161. it.find('#mode').addClass('fa fa-code-fork');
  162. }
  163. },
  164. // remove
  165. remove: function() {
  166. // trigger remove event
  167. this.select_genome.remove();
  168. this.select_extension.remove();
  169. // call the base class remove method
  170. Backbone.View.prototype.remove.apply(this);
  171. },
  172. //
  173. // handle model events
  174. //
  175. // genome
  176. _refreshGenome: function() {
  177. // update genome info on screen
  178. var genome = this.model.get('genome');
  179. this.select_genome.value(genome);
  180. },
  181. // progress
  182. _refreshInfo: function() {
  183. // write error message
  184. var info = this.model.get('info');
  185. if (info) {
  186. this.$el.find('#info').html('<strong>Failed: </strong>' + info).show();
  187. } else {
  188. this.$el.find('#info').hide();
  189. }
  190. },
  191. // progress
  192. _refreshPercentage : function() {
  193. var percentage = parseInt(this.model.get('percentage'));
  194. this.$el.find('.progress-bar').css({ width : percentage + '%' });
  195. if (percentage != 100)
  196. this.$el.find('#percentage').html(percentage + '%');
  197. else
  198. this.$el.find('#percentage').html('Adding to history...');
  199. },
  200. // status
  201. _refreshStatus : function() {
  202. // get element
  203. var it = this.$el;
  204. // identify new status
  205. var status = this.model.get('status');
  206. var status_class = this.status_classes[status];
  207. // identify symbol and reset classes
  208. var sy = this.$el.find('#symbol');
  209. sy.removeClass();
  210. // set new status class
  211. sy.addClass(status_class);
  212. // enable form fields
  213. if (status == 'init') {
  214. // select fields
  215. this.select_genome.enable();
  216. this.select_extension.enable();
  217. // default fields
  218. it.find('#text-content').attr('disabled', false);
  219. it.find('#space_to_tabs').attr('disabled', false);
  220. } else {
  221. // select fields
  222. this.select_genome.disable();
  223. this.select_extension.disable();
  224. // default fields
  225. it.find('#text-content').attr('disabled', true);
  226. it.find('#space_to_tabs').attr('disabled', true);
  227. }
  228. // success
  229. if (status == 'success') {
  230. it.addClass('success');
  231. it.find('#percentage').html('100%');
  232. }
  233. // error
  234. if (status == 'error') {
  235. it.addClass('danger');
  236. it.find('.progress').remove();
  237. }
  238. },
  239. // refresh size
  240. _refreshFileSize: function() {
  241. var count = this.model.get('file_size');
  242. this.$el.find('#size').html(Utils.bytesToString (count));
  243. },
  244. //
  245. // handle ui events
  246. //
  247. // remove row
  248. _removeRow: function() {
  249. // get current status
  250. var status = this.model.get('status');
  251. // only remove from queue if not in processing line
  252. if (status == 'init' || status == 'success' || status == 'error') {
  253. this.app.collection.remove(this.model);
  254. }
  255. },
  256. // attach file info popup
  257. _showExtensionInfo : function() {
  258. // initialize
  259. var $el = $(this.el).find('#extension-info');
  260. var extension = this.model.get('extension');
  261. var title = this.select_extension.text();
  262. var description = _.findWhere(this.app.list_extensions, {'id': extension});
  263. // create popup
  264. if (!this.extension_popup) {
  265. this.extension_popup = new Popover.View({
  266. placement: 'bottom',
  267. container: $el
  268. });
  269. }
  270. // show / hide popup
  271. if (!this.extension_popup.visible) {
  272. this.extension_popup.title(title);
  273. this.extension_popup.empty();
  274. this.extension_popup.append(this._templateDescription(description));
  275. this.extension_popup.show();
  276. } else {
  277. this.extension_popup.hide();
  278. }
  279. },
  280. // attach file info popup
  281. _showSettings : function() {
  282. // check if popover is visible
  283. if (!this.settings.visible) {
  284. // show popover
  285. this.settings.empty();
  286. this.settings.append((new UploadSettings(this)).$el);
  287. this.settings.show();
  288. } else {
  289. // hide popover
  290. this.settings.hide();
  291. }
  292. },
  293. // template
  294. _templateDescription: function(options) {
  295. if (options.description) {
  296. var tmpl = options.description;
  297. if (options.description_url) {
  298. tmpl += '&nbsp;(<a href="' + options.description_url + '" target="_blank">read more</a>)';
  299. }
  300. return tmpl;
  301. } else {
  302. return 'There is no description available for this file extension.';
  303. }
  304. },
  305. // template
  306. _template: function(options) {
  307. return '<tr id="upload-item-' + options.id + '" class="upload-item">' +
  308. '<td>' +
  309. '<div style="position: relative;">' +
  310. '<div id="mode"></div>' +
  311. '<div id="title" class="title"></div>' +
  312. '<div id="text" class="text">' +
  313. '<div class="text-info">You can tell Galaxy to download data from web by entering URL in this box (one per line). You can also directly paste the contents of a file.</div>' +
  314. '<textarea id="text-content" class="text-content form-control"></textarea>' +
  315. '</div>' +
  316. '</div>' +
  317. '</td>' +
  318. '<td>' +
  319. '<div id="size" class="size"></div>' +
  320. '</td>' +
  321. '<td>' +
  322. '<div id="extension" class="extension" style="float: left;"/>&nbsp;&nbsp' +
  323. '<div id="extension-info" class="upload-icon-button fa fa-search"/>' +
  324. '</td>' +
  325. '<td>' +
  326. '<div id="genome" class="genome" />' +
  327. '</td>' +
  328. '<td><div id="settings" class="upload-icon-button fa fa-gear"></div>' +
  329. '<td>' +
  330. '<div id="info" class="info">' +
  331. '<div class="progress">' +
  332. '<div class="progress-bar progress-bar-success"></div>' +
  333. '<div id="percentage" class="percentage">0%</div>' +
  334. '</div>' +
  335. '</div>' +
  336. '</td>' +
  337. '<td>' +
  338. '<div id="symbol" class="' + this.status_classes.init + '"></div>' +
  339. '</td>' +
  340. '</tr>';
  341. }
  342. });
  343. });