mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Refactor tabular chunked display into Backbone and use for displaying tabular data.
This commit is contained in:
+164
-1
@@ -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( $('<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
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
@@ -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}});
|
||||
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}});
|
||||
@@ -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)});
|
||||
}
|
||||
}
|
||||
});
|
||||
$('#loading_indicator').ajaxStart(function(){
|
||||
$(this).show();
|
||||
}).ajaxStop(function(){
|
||||
$(this).hide();
|
||||
// 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
|
||||
});
|
||||
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>
|
||||
|
||||
Reference in New Issue
Block a user