diff --git a/static/scripts/mvc/data.js b/static/scripts/mvc/data.js index ed244a3e7c5..451ec2960ad 100644 --- a/static/scripts/mvc/data.js +++ b/static/scripts/mvc/data.js @@ -1,3 +1,4 @@ +// Additional dependencies: jQuery, underscore. define(["libs/backbone/backbone-relational"], function() { /** @@ -46,13 +47,175 @@ var Dataset = Backbone.RelationalModel.extend({ urlRoot: galaxy_paths.get('datasets_url') }); +/** + * A tabular dataset. This object extends dataset to provide incremental chunked data. + */ +var TabularDataset = Dataset.extend({ + defaults: _.extend({}, Dataset.prototype.defaults, { + chunk_url: null, + first_data_chunk: null, + chunk_index: -1, + at_eof: false + }), + + initialize: function(options) { + Dataset.prototype.initialize.call(this); + + // If first data chunk is available, next + // chunk is 1. + chunk_index = (this.attributes.first_data_chunk ? 1 : 0); + }, + + /** + * Set first data chunk; useful when initializing on the server side. + */ + set_first_chunk: function(chunk) { + this.attributes.first_data_chunk = chunk; + this.attributes.chunk_index = 1; + }, + + /** + * Returns a jQuery Deferred object that resolves to the next data chunk or null if at EOF. + */ + get_next_chunk: function() { + // If already at end of file, do nothing. + if (this.attributes.at_eof) { + return null; + } + + // Get next chunk. + var self = this, + next_chunk = $.Deferred(); + $.getJSON(this.attributes.chunk_url, { + chunk: self.attributes.chunk_index++ + }).success(function(chunk) { + var rval; + if (chunk.ck_data !== '') { + // Found chunk. + rval = chunk; + } + else { + // At EOF. + self.attributes.at_eof = true; + rval = null; + } + next_chunk.resolve(rval); + }); + + return next_chunk; + } +}); + var DatasetCollection = Backbone.Collection.extend({ model: Dataset }); +/** + * Provides table-based, dynamic view of a tabular dataset. + */ +var TabularDatasetChunkedView = Backbone.View.extend({ + + initialize: function(options) {}, + + render: function() { + // Add loading indicator div. + this.$el.append( $('
').attr('id', 'loading_indicator') ); + + // Add data table and header. + var data_table = $('').attr({ + id: 'content_table', + cellpadding: 0 + }); + this.$el.append(data_table); + var column_names = this.model.get_metadata('column_names'); + if (column_names) { + data_table.append(''); + } + + // Add first chunk. + var first_chunk = this.model.get('first_data_chunk'); + if (first_chunk) { + this._renderChunk(first_chunk); + } + + // Show new chunks during scrolling. + var self = this; + $(window).scroll(function() { + if ($(window).scrollTop() === $(document).height() - $(window).height()) { + $.when(self.model.get_next_chunk()).then(function(result) { + if (result) { + self._renderChunk(result); + } + }); + } + }); + $('#loading_indicator').ajaxStart(function(){ + $(this).show(); + }).ajaxStop(function(){ + $(this).hide(); + }); + }, + + // -- Helper functions. -- + + _renderCell: function(cell_contents, index, colspan) { + var column_types = this.model.get_metadata('column_types'); + if (colspan !== undefined) { + return $(''), + num_columns = this.model.get_metadata('columns'); + if (cells.length === num_columns) { + _.each(cells, function(cell_contents, index) { + row.append(this._renderCell(cell_contents, index)); + }, this); + } + else if (cells.length > num_columns) { + // SAM file or like format with optional metadata included. + _.each(cells.slice(0, num_columns - 1), function(cell_contents, index) { + row.append(this._renderCell(cell_contents, index)); + }, this); + row.append(this._renderCell(cells.slice(num_columns - 1).join('\t'), num_columns - 1)); + } + else if (num_columns > 5 && cells.length === num_columns - 1 ) { + // SAM file or like format with optional metadata missing. + _.each(cells, function(cell_contents, index) { + row.append(this._renderCell(cell_contents, index)); + }, this); + row.append($('
' + column_names.join('') + '
').attr('colspan', colspan).addClass('stringalign').text(cell_contents); + } + else if (column_types[index] === 'str' || column_types === 'list') { + /* Left align all str columns, right align the rest */ + return $('').addClass('stringalign').text(cell_contents); + } + else { + return $('').text(cell_contents); + } + }, + + _renderRow: function(line) { + // Check length of cells to ensure this is a complete row. + var cells = line.split('\t'), + row = $('
')); + } + else { + // Comment line, just return the one cell. + row.append(this._renderCell(line, 0, num_columns)); + } + return row; + }, + + _renderChunk: function(chunk) { + var data_table = this.$el.find('table'); + _.each(chunk.ck_data.split('\n'), function(line, index) { + data_table.append(this._renderRow(line)); + }, this); + } +}); + return { Dataset: Dataset, - DatasetCollection: DatasetCollection + TabularDataset: TabularDataset, + DatasetCollection: DatasetCollection, + TabularDatasetChunkedView: TabularDatasetChunkedView }; }); diff --git a/static/scripts/packed/mvc/data.js b/static/scripts/packed/mvc/data.js index 3f75ccc4781..fb7d31d1ce5 100644 --- a/static/scripts/packed/mvc/data.js +++ b/static/scripts/packed/mvc/data.js @@ -1 +1 @@ -define(["libs/backbone/backbone-relational"],function(){var a=Backbone.RelationalModel.extend({});var b=Backbone.RelationalModel.extend({defaults:{id:"",type:"",name:"",hda_ldda:"hda",metadata:null},initialize:function(){var d=new a();_.each(_.keys(this.attributes),function(e){if(e.indexOf("metadata_")===0){var f=e.split("metadata_")[1];d.set(f,this.attributes[e]);delete this.attributes[e]}},this);this.set("metadata",d)},get_metadata:function(d){return this.attributes.metadata.get(d)},urlRoot:galaxy_paths.get("datasets_url")});var c=Backbone.Collection.extend({model:b});return{Dataset:b,DatasetCollection:c}}); \ No newline at end of file +define(["libs/backbone/backbone-relational"],function(){var b=Backbone.RelationalModel.extend({});var c=Backbone.RelationalModel.extend({defaults:{id:"",type:"",name:"",hda_ldda:"hda",metadata:null},initialize:function(){var f=new b();_.each(_.keys(this.attributes),function(g){if(g.indexOf("metadata_")===0){var h=g.split("metadata_")[1];f.set(h,this.attributes[g]);delete this.attributes[g]}},this);this.set("metadata",f)},get_metadata:function(f){return this.attributes.metadata.get(f)},urlRoot:galaxy_paths.get("datasets_url")});var a=c.extend({defaults:_.extend({},c.prototype.defaults,{chunk_url:null,first_data_chunk:null,chunk_index:-1,at_eof:false}),initialize:function(f){c.prototype.initialize.call(this);chunk_index=(this.attributes.first_data_chunk?1:0)},set_first_chunk:function(f){this.attributes.first_data_chunk=f;this.attributes.chunk_index=1},get_next_chunk:function(){if(this.attributes.at_eof){return null}var f=this,g=$.Deferred();$.getJSON(this.attributes.chunk_url,{chunk:f.attributes.chunk_index++}).success(function(h){var i;if(h.ck_data!==""){i=h}else{f.attributes.at_eof=true;i=null}g.resolve(i)});return g}});var e=Backbone.Collection.extend({model:c});var d=Backbone.View.extend({initialize:function(f){},render:function(){this.$el.append($("
").attr("id","loading_indicator"));var i=$("").attr({id:"content_table",cellpadding:0});this.$el.append(i);var f=this.model.get_metadata("column_names");if(f){i.append("")}var h=this.model.get("first_data_chunk");if(h){this._renderChunk(h)}var g=this;$(window).scroll(function(){if($(window).scrollTop()===$(document).height()-$(window).height()){$.when(g.model.get_next_chunk()).then(function(j){if(j){g._renderChunk(j)}})}});$("#loading_indicator").ajaxStart(function(){$(this).show()}).ajaxStop(function(){$(this).hide()})},_renderCell:function(h,f,i){var g=this.model.get_metadata("column_types");if(i!==undefined){return $(""),h=this.model.get_metadata("columns");if(g.length===h){_.each(g,function(k,j){i.append(this._renderCell(k,j))},this)}else{if(g.length>h){_.each(g.slice(0,h-1),function(k,j){i.append(this._renderCell(k,j))},this);i.append(this._renderCell(g.slice(h-1).join("\t"),h-1))}else{if(h>5&&g.length===h-1){_.each(g,function(k,j){i.append(this._renderCell(k,j))},this);i.append($("
"+f.join("")+"
").attr("colspan",i).addClass("stringalign").text(h)}else{if(g[f]==="str"||g==="list"){return $("").addClass("stringalign").text(h)}else{return $("").text(h)}}},_renderRow:function(f){var g=f.split("\t"),i=$("
"))}else{i.append(this._renderCell(f,0,h))}}}return i},_renderChunk:function(f){var g=this.$el.find("table");_.each(f.ck_data.split("\n"),function(h,i){g.append(this._renderRow(h))},this)}});return{Dataset:c,TabularDataset:a,DatasetCollection:e,TabularDatasetChunkedView:d}}); \ No newline at end of file diff --git a/templates/webapps/galaxy/dataset/tabular_chunked.mako b/templates/webapps/galaxy/dataset/tabular_chunked.mako index 96068125477..3055c3835fa 100644 --- a/templates/webapps/galaxy/dataset/tabular_chunked.mako +++ b/templates/webapps/galaxy/dataset/tabular_chunked.mako @@ -5,91 +5,31 @@ <%def name="javascripts()"> ${parent.javascripts()} + ${h.js( "libs/require" )} @@ -97,7 +37,3 @@ <%def name="stylesheets()"> ${parent.stylesheets()} - -
- -