1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/2faf4a9871bb/ changeset: 2faf4a9871bb user: jgoecks date: 2013-02-04 18:37:32 summary: Refactor tabular chunked display into Backbone and use for displaying tabular data. affected #: 3 files diff -r 909868dda8812fcba2215a6eb77bdbaf71c6dfd0 -r 2faf4a9871bb58da2b16d1a8929a53c68f951cc0 static/scripts/mvc/data.js --- 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 @@ 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( $('<div/>').attr('id', 'loading_indicator') ); + + // Add data table and header. + var data_table = $('<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('<tr><th>' + column_names.join('</th><th>') + '</th></tr>'); + } + + // 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 $('<td>').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 $('<td>').addClass('stringalign').text(cell_contents); + } + else { + return $('<td>').text(cell_contents); + } + }, + + _renderRow: function(line) { + // Check length of cells to ensure this is a complete row. + var cells = line.split('\t'), + row = $('<tr>'), + 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($('<td>')); + } + 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 -r 909868dda8812fcba2215a6eb77bdbaf71c6dfd0 -r 2faf4a9871bb58da2b16d1a8929a53c68f951cc0 static/scripts/packed/mvc/data.js --- a/static/scripts/packed/mvc/data.js +++ b/static/scripts/packed/mvc/data.js @@ -1,1 +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($("<div/>").attr("id","loading_indicator"));var i=$("<table/>").attr({id:"content_table",cellpadding:0});this.$el.append(i);var f=this.model.get_metadata("column_names");if(f){i.append("<tr><th>"+f.join("</th><th>")+"</th></tr>")}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 $("<td>").attr("colspan",i).addClass("stringalign").text(h)}else{if(g[f]==="str"||g==="list"){return $("<td>").addClass("stringalign").text(h)}else{return $("<td>").text(h)}}},_renderRow:function(f){var g=f.split("\t"),i=$("<tr>"),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($("<td>"))}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 -r 909868dda8812fcba2215a6eb77bdbaf71c6dfd0 -r 2faf4a9871bb58da2b16d1a8929a53c68f951cc0 templates/webapps/galaxy/dataset/tabular_chunked.mako --- 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" )} <script type="text/javascript"> - var DATASET_URL = "${h.url_for( controller='/dataset', action='display', dataset_id=trans.security.encode_id( dataset.id ))}"; - var COLUMN_NUMBER = ${column_number}; - var COLUMN_TYPES = ${column_types}; - var COLUMN_NAMES = ${column_names}; + require.config({ + baseUrl: "${h.url_for('/static/scripts')}", + shim: { + "libs/underscore": { exports: "_" }, + "libs/backbone/backbone": { exports: "Backbone" }, + "libs/backbone/backbone-relational": ["libs/backbone/backbone"] + } + }); - var chunk = ${chunk}; - var current_chunk = 0; + require([ 'mvc/data' ], function(data) { - function renderCell(cell_contents, index, colspan){ - if (colspan !== undefined){ - return $('<td>').attr('colspan', colspan).addClass('stringalign').text(cell_contents); - } - else if (COLUMN_TYPES[index] == 'str' || COLUMN_TYPES[index] == 'list'){ - /* Left align all str columns, right align the rest */ - return $('<td>').addClass('stringalign').text(cell_contents);; - } - else{ - return $('<td>').text(cell_contents); - } - } - - function renderRow(line){ - /* Check length of cells to ensure this is a complete row. */ - var cells = line.split('\t'); - var row = $('<tr>'); - if (cells.length == COLUMN_NUMBER){ - $.each(cells, function(index, cell_contents){ - row.append(renderCell(cell_contents, index)); - }); - } - else if(cells.length > COLUMN_NUMBER){ - /* SAM file or like format with optional metadata included */ - $.each(cells.slice(0, COLUMN_NUMBER -1), function(index, cell_contents){ - row.append(renderCell(cell_contents, index)); - }); - row.append(renderCell(cells.slice(COLUMN_NUMBER -1).join('\t'), COLUMN_NUMBER-1)); - } - else if(COLUMN_NUMBER > 5 && cells.length == COLUMN_NUMBER - 1 ){ - /* SAM file or like format with optional metadata missing */ - $.each(cells, function(index, cell_contents){ - row.append(renderCell(cell_contents, index)); - }); - row.append($('<td>')); - } - else{ - /* Comment line, just return the one cell*/ - row.append(renderCell(line, 0, COLUMN_NUMBER)); - } - return row; - } - - function renderChunk(chunk){ - var table = $('#content_table'); - if (chunk.ck_data == ""){ - current_chunk = -1; - } - else if(chunk.ck_index === current_chunk + 1){ - if (current_chunk === 0 && COLUMN_NAMES){ - table.append('<tr><th>' + COLUMN_NAMES.join('</th><th>') + '</th></tr>'); - } - var lines = chunk.ck_data.split('\n'); - $.each(lines, function(index, line){ - table.append(renderRow(line)); - }); - current_chunk = chunk.ck_index; - } - } - - $(document).ready(function(){ - renderChunk(chunk); - $(window).scroll(function(){ - if ($(window).scrollTop() == $(document).height() - $(window).height()){ - if (current_chunk !== -1){ - $.getJSON(DATASET_URL, - {chunk: current_chunk}, - function(result){renderChunk(result)}); - } - } + // Set up dataset and attributes. + var dataset = new data.TabularDataset( ${h.to_json_string( dataset.get_api_value() )} ); + dataset.set('chunk_url', + "${h.url_for( controller='/dataset', action='display', dataset_id=trans.security.encode_id( dataset.id ))}"); + dataset.set_first_chunk(${chunk}) + + // Set up, render, and add view. + var dataset_view = new data.TabularDatasetChunkedView({ + model: dataset }); - $('#loading_indicator').ajaxStart(function(){ - $(this).show(); - }).ajaxStop(function(){ - $(this).hide(); - }); + dataset_view.render(); + $('body').append(dataset_view.$el); }); </script></%def> @@ -97,7 +37,3 @@ <%def name="stylesheets()"> ${parent.stylesheets()} </%def> - -<div id="loading_indicator" ></div> -<table id="content_table" cellpadding="0"> -</table> Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.