PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/afgane/galaxy-central
JavaScript | 377 lines | 281 code | 42 blank | 54 comment | 42 complexity | bff4be13ad572a60cb2e0c096596e27d MD5 | raw file
Possible License(s): CC-BY-3.0
  1. define([
  2. "galaxy.masthead",
  3. "utils/utils",
  4. "libs/toastr",
  5. "mvc/library/library-model",
  6. "mvc/library/library-folderrow-view",
  7. "mvc/library/library-dataset-view"
  8. ],
  9. function(mod_masthead,
  10. mod_utils,
  11. mod_toastr,
  12. mod_library_model,
  13. mod_library_folderrow_view,
  14. mod_library_dataset_view
  15. ) {
  16. var FolderListView = Backbone.View.extend({
  17. el : '#folder_items_element',
  18. // progress percentage
  19. progress: 0,
  20. // progress rate per one item
  21. progressStep: 1,
  22. folderContainer: null,
  23. sort: 'asc',
  24. events: {
  25. 'click #select-all-checkboxes' : 'selectAll',
  26. 'click .dataset_row' : 'selectClickedRow',
  27. 'click .sort-folder-link' : 'sortColumnClicked'
  28. },
  29. collection: null,
  30. defaults: {
  31. include_deleted: false,
  32. page_count: null,
  33. show_page: null
  34. },
  35. /**
  36. * Initialize and fetch the folder from the server.
  37. * @param {object} options an object with options
  38. */
  39. initialize : function( options ){
  40. this.options = _.defaults( this.options || {}, this.defaults, options );
  41. this.modal = null;
  42. // map of folder item ids to item views = cache
  43. this.rowViews = {};
  44. // create a collection of folder items for this view
  45. this.collection = new mod_library_model.Folder();
  46. // start to listen if someone modifies the collection
  47. this.listenTo( this.collection, 'add', this.renderOne );
  48. this.listenTo( this.collection, 'remove', this.removeOne );
  49. this.fetchFolder();
  50. },
  51. fetchFolder: function( options ){
  52. var options = options || {};
  53. this.options.include_deleted = options.include_deleted;
  54. var that = this;
  55. this.folderContainer = new mod_library_model.FolderContainer( { id: this.options.id } );
  56. this.folderContainer.url = this.folderContainer.attributes.urlRoot + this.options.id + '/contents';
  57. if ( this.options.include_deleted ){
  58. this.folderContainer.url = this.folderContainer.url + '?include_deleted=true';
  59. }
  60. this.folderContainer.fetch({
  61. success: function( folder_container ) {
  62. that.folder_container = folder_container;
  63. that.render();
  64. },
  65. error: function( model, response ){
  66. if ( typeof response.responseJSON !== "undefined" ){
  67. mod_toastr.error( response.responseJSON.err_msg + ' Click this to go back.', '', { onclick: function() { Galaxy.libraries.library_router.back(); } } );
  68. } else {
  69. mod_toastr.error( 'An error ocurred. Click this to go back.', '', { onclick: function() { Galaxy.libraries.library_router.back(); } } );
  70. }
  71. }
  72. });
  73. },
  74. render: function ( options ){
  75. this.options = _.extend( this.options, options );
  76. var template = this.templateFolder();
  77. $(".tooltip").hide();
  78. // find the upper id in the full path
  79. var path = this.folderContainer.attributes.metadata.full_path;
  80. var upper_folder_id;
  81. if ( path.length === 1 ){ // the library is above us
  82. upper_folder_id = 0;
  83. } else {
  84. upper_folder_id = path[ path.length-2 ][ 0 ];
  85. }
  86. this.$el.html( template( {
  87. path: this.folderContainer.attributes.metadata.full_path,
  88. parent_library_id: this.folderContainer.attributes.metadata.parent_library_id,
  89. id: this.options.id,
  90. upper_folder_id: upper_folder_id,
  91. order: this.sort
  92. } ) );
  93. // when dataset_id is present render its details too
  94. if ( this.options.dataset_id ){
  95. row = _.findWhere( that.rowViews, { id: this.options.dataset_id } );
  96. if ( row ) {
  97. row.showDatasetDetails();
  98. } else {
  99. mod_toastr.error( 'Requested dataset not found. Showing folder instead.' );
  100. }
  101. } else {
  102. if ( this.options.show_page === null || this.options.show_page < 1 ){
  103. this.options.show_page = 1;
  104. }
  105. this.paginate();
  106. }
  107. $("#center [data-toggle]").tooltip();
  108. $("#center").css('overflow','auto');
  109. },
  110. paginate: function( options ){
  111. this.options = _.extend( this.options, options );
  112. if ( this.options.show_page === null || this.options.show_page < 1 ){
  113. this.options.show_page = 1;
  114. }
  115. this.options.total_items_count = this.folder_container.get( 'folder' ).models.length;
  116. this.options.page_count = Math.ceil( this.options.total_items_count / Galaxy.libraries.preferences.get( 'folder_page_size' ) );
  117. var page_start = ( Galaxy.libraries.preferences.get( 'folder_page_size' ) * ( this.options.show_page - 1 ) );
  118. var items_to_render = null;
  119. items_to_render = this.folder_container.get( 'folder' ).models.slice( page_start, page_start + Galaxy.libraries.preferences.get( 'folder_page_size' ) );
  120. this.options.items_shown = items_to_render.length;
  121. // User requests page with no items
  122. if ( Galaxy.libraries.preferences.get( 'folder_page_size' ) * this.options.show_page > ( this.options.total_items_count + Galaxy.libraries.preferences.get( 'folder_page_size' ) ) ){
  123. items_to_render = [];
  124. }
  125. Galaxy.libraries.folderToolbarView.renderPaginator( this.options );
  126. this.collection.reset();
  127. this.addAll( items_to_render )
  128. },
  129. /**
  130. * Adds all given models to the collection.
  131. * @param {array of Item or FolderAsModel} array of models that should
  132. * be added to the view's collection.
  133. */
  134. addAll: function( models ){
  135. _.each(models, function( model ) {
  136. Galaxy.libraries.folderListView.collection.add( model );
  137. });
  138. $( "#center [data-toggle]" ).tooltip();
  139. this.checkEmptiness();
  140. this.postRender();
  141. },
  142. /**
  143. * Call this after all models are added to the collection
  144. * to ensure that the folder toolbar will show proper options
  145. * and that event will be bound on all subviews.
  146. */
  147. postRender: function(){
  148. var fetched_metadata = this.folderContainer.attributes.metadata;
  149. fetched_metadata.contains_file = typeof this.collection.findWhere({type: 'file'}) !== 'undefined';
  150. Galaxy.libraries.folderToolbarView.configureElements(fetched_metadata);
  151. $('.library-row').hover(function() {
  152. $(this).find('.show_on_hover').show();
  153. }, function () {
  154. $(this).find('.show_on_hover').hide();
  155. });
  156. },
  157. /**
  158. * Iterates this view's collection and calls the render
  159. * function for each. Also binds the hover behavior.
  160. */
  161. renderAll: function(){
  162. var that = this;
  163. _.each( this.collection.models.reverse(), function( model ) {
  164. that.renderOne( model );
  165. });
  166. this.postRender();
  167. },
  168. /**
  169. * Creates a view for the given model and adds it to the folder view.
  170. * @param {Item or FolderAsModel} model of the view that will be rendered
  171. */
  172. renderOne: function(model){
  173. if (model.get('type') !== 'folder'){
  174. this.options.contains_file = true;
  175. // model.set('readable_size', this.size_to_string(model.get('file_size')));
  176. }
  177. model.set('folder_id', this.id);
  178. var rowView = new mod_library_folderrow_view.FolderRowView(model);
  179. // save new rowView to cache
  180. this.rowViews[model.get('id')] = rowView;
  181. this.$el.find('#first_folder_item').after(rowView.el);
  182. $('.library-row').hover(function() {
  183. $(this).find('.show_on_hover').show();
  184. }, function () {
  185. $(this).find('.show_on_hover').hide();
  186. });
  187. },
  188. /**
  189. * removes the view of the given model from the DOM
  190. * @param {Item or FolderAsModel} model of the view that will be removed
  191. */
  192. removeOne: function( model ){
  193. this.$el.find( '#' + model.id ).remove();
  194. },
  195. /** Checks whether the list is empty and adds/removes the message */
  196. checkEmptiness : function(){
  197. if ((this.$el.find('.dataset_row').length === 0) && (this.$el.find('.folder_row').length === 0)){
  198. this.$el.find('.empty-folder-message').show();
  199. } else {
  200. this.$el.find('.empty-folder-message').hide();
  201. }
  202. },
  203. /** User clicked the table heading = he wants to sort stuff */
  204. sortColumnClicked : function(event){
  205. event.preventDefault();
  206. if (this.sort === 'asc'){
  207. this.sortFolder('name','desc');
  208. this.sort = 'desc';
  209. } else {
  210. this.sortFolder('name','asc');
  211. this.sort = 'asc';
  212. }
  213. this.render();
  214. this.renderAll();
  215. this.checkEmptiness();
  216. },
  217. /**
  218. * Sorts the underlying collection according to the parameters received.
  219. * Currently supports only sorting by name.
  220. */
  221. sortFolder: function(sort_by, order){
  222. if (sort_by === 'name'){
  223. if (order === 'asc'){
  224. return this.collection.sortByNameAsc();
  225. } else if (order === 'desc'){
  226. return this.collection.sortByNameDesc();
  227. }
  228. }
  229. },
  230. /**
  231. * User clicked the checkbox in the table heading
  232. * @param {context} event
  233. */
  234. selectAll : function (event) {
  235. var selected = event.target.checked;
  236. that = this;
  237. // Iterate each checkbox
  238. $(':checkbox', '#folder_list_body').each(function() {
  239. this.checked = selected;
  240. $row = $(this.parentElement.parentElement);
  241. // Change color of selected/unselected
  242. if (selected) {
  243. that.makeDarkRow($row);
  244. } else {
  245. that.makeWhiteRow($row);
  246. }
  247. });
  248. },
  249. /**
  250. * Check checkbox if user clicks on the whole row or
  251. * on the checkbox itself
  252. */
  253. selectClickedRow : function (event) {
  254. var checkbox = '';
  255. var $row;
  256. var source;
  257. if (event.target.localName === 'input'){
  258. checkbox = event.target;
  259. $row = $(event.target.parentElement.parentElement);
  260. source = 'input';
  261. } else if (event.target.localName === 'td') {
  262. checkbox = $("#" + event.target.parentElement.id).find(':checkbox')[0];
  263. $row = $(event.target.parentElement);
  264. source = 'td';
  265. }
  266. if (checkbox.checked){
  267. if (source==='td'){
  268. checkbox.checked = '';
  269. this.makeWhiteRow($row);
  270. } else if (source==='input') {
  271. this.makeDarkRow($row);
  272. }
  273. } else {
  274. if (source==='td'){
  275. checkbox.checked = 'selected';
  276. this.makeDarkRow($row);
  277. } else if (source==='input') {
  278. this.makeWhiteRow($row);
  279. }
  280. }
  281. },
  282. makeDarkRow: function($row){
  283. $row.removeClass('light').addClass('dark');
  284. $row.find('a').removeClass('light').addClass('dark');
  285. $row.find('.fa-file-o').removeClass('fa-file-o').addClass('fa-file');
  286. },
  287. makeWhiteRow: function($row){
  288. $row.removeClass('dark').addClass('light');
  289. $row.find('a').removeClass('dark').addClass('light');
  290. $row.find('.fa-file').removeClass('fa-file').addClass('fa-file-o');
  291. },
  292. templateFolder : function (){
  293. var tmpl_array = [];
  294. // BREADCRUMBS
  295. tmpl_array.push('<ol class="breadcrumb">');
  296. tmpl_array.push(' <li><a title="Return to the list of libraries" href="#">Libraries</a></li>');
  297. tmpl_array.push(' <% _.each(path, function(path_item) { %>');
  298. tmpl_array.push(' <% if (path_item[0] != id) { %>');
  299. tmpl_array.push(' <li><a title="Return to this folder" href="#/folders/<%- path_item[0] %>"><%- path_item[1] %></a> </li> ');
  300. tmpl_array.push( '<% } else { %>');
  301. tmpl_array.push(' <li class="active"><span title="You are in this folder"><%- path_item[1] %></span></li>');
  302. tmpl_array.push(' <% } %>');
  303. tmpl_array.push(' <% }); %>');
  304. tmpl_array.push('</ol>');
  305. // FOLDER CONTENT
  306. tmpl_array.push('<table data-library-id="<%- parent_library_id %>" id="folder_table" class="grid table table-condensed">');
  307. tmpl_array.push(' <thead>');
  308. tmpl_array.push(' <th class="button_heading"></th>');
  309. tmpl_array.push(' <th style="text-align: center; width: 20px; " title="Check to select all datasets"><input id="select-all-checkboxes" style="margin: 0;" type="checkbox"></th>');
  310. tmpl_array.push(' <th><a class="sort-folder-link" title="Click to reverse order" href="#">name</a> <span title="Sorted alphabetically" class="fa fa-sort-alpha-<%- order %>"></span></th>');
  311. tmpl_array.push(' <th style="width:5%;">data type</th>');
  312. tmpl_array.push(' <th style="width:10%;">size</th>');
  313. tmpl_array.push(' <th style="width:160px;">time updated (UTC)</th>');
  314. tmpl_array.push(' <th style="width:10%;"></th> ');
  315. tmpl_array.push(' </thead>');
  316. tmpl_array.push(' <tbody id="folder_list_body">');
  317. tmpl_array.push(' <tr id="first_folder_item">');
  318. tmpl_array.push(' <td><a href="#<% if (upper_folder_id !== 0){ print("folders/" + upper_folder_id)} %>" title="Go to parent folder" class="btn_open_folder btn btn-default btn-xs">..<a></td>');
  319. tmpl_array.push(' <td></td>');
  320. tmpl_array.push(' <td></td>');
  321. tmpl_array.push(' <td></td>');
  322. tmpl_array.push(' <td></td>');
  323. tmpl_array.push(' <td></td>');
  324. tmpl_array.push(' <td></td>');
  325. tmpl_array.push(' </tr>');
  326. tmpl_array.push(' </tbody>');
  327. tmpl_array.push('</table>');
  328. tmpl_array.push('<div class="empty-folder-message" style="display:none;">This folder is either empty or you do not have proper access permissions to see the contents. If you expected something to show up please consult the <a href="https://wiki.galaxyproject.org/Admin/DataLibraries/LibrarySecurity" target="_blank">library security wikipage</a> or visit the <a href="https://biostar.usegalaxy.org/" target="_blank">Galaxy support site</a>.</div>');
  329. return _.template(tmpl_array.join(''));
  330. }
  331. });
  332. return {
  333. FolderListView: FolderListView
  334. };
  335. });