[#116,view/grid][m]: fixed header on grid table so you can scroll and header stays fixed - fixes #116.

* [s] in changes by [m] in effort
* pretty painful to do and we now have to set width of columns explicitly - though this will be useful going forward if we allow adjustable width columns.
* even support different width scrollbars in different browsers (have not tested in IE though!)
* remaining bug is that we have an overhang in header when no scrollbar for body (probably not that hard to fix ...)
This commit is contained in:
Rufus Pollock
2012-05-17 13:22:42 +01:00
parent 310a008537
commit 7963dc2a09
2 changed files with 91 additions and 10 deletions

View File

@@ -130,8 +130,9 @@ my.Grid = Backbone.View.extend({
// ======================================================
// #### Templating
template: ' \
<div class="table-container"> \
<table class="recline-grid table-striped table-condensed" cellspacing="0"> \
<thead> \
<thead class="fixed-header"> \
<tr> \
{{#notEmpty}} \
<th class="column-header"> \
@@ -144,7 +145,7 @@ my.Grid = Backbone.View.extend({
</th> \
{{/notEmpty}} \
{{#fields}} \
<th class="column-header {{#hidden}}hidden{{/hidden}}" data-field="{{id}}"> \
<th class="column-header {{#hidden}}hidden{{/hidden}}" data-field="{{id}}" style="width: {{width}}px;"> \
<div class="btn-group column-header-menu"> \
<a class="btn dropdown-toggle" data-toggle="dropdown"><i class="icon-cog"></i><span class="caret"></span></a> \
<ul class="dropdown-menu data-table-menu pull-right"> \
@@ -163,17 +164,24 @@ my.Grid = Backbone.View.extend({
<span class="column-header-name">{{label}}</span> \
</th> \
{{/fields}} \
<th class="last-header" style="width: {{lastHeaderWidth}}px; padding: 0; margin: 0;"></th> \
</tr> \
</thead> \
<tbody></tbody> \
<tbody class="scrollContent"></tbody> \
</table> \
</div> \
',
toTemplateJSON: function() {
var self = this;
var modelData = this.model.toJSON();
modelData.notEmpty = ( this.fields.length > 0 );
// TODO: move this sort of thing into a toTemplateJSON method on Dataset?
modelData.fields = _.map(this.fields, function(field) { return field.toJSON(); });
modelData.fields = _.map(this.fields, function(field) {
return field.toJSON();
});
// last header width = scroll bar - border (2px) */
modelData.lastHeaderWidth = this.scrollbarDimensions.width - 2;
return modelData;
},
render: function() {
@@ -181,6 +189,20 @@ my.Grid = Backbone.View.extend({
this.fields = this.model.fields.filter(function(field) {
return _.indexOf(self.state.get('hiddenFields'), field.id) == -1;
});
this.scrollbarDimensions = this.scrollbarDimensions || this._scrollbarSize(); // skip measurement if already have dimensions
var numFields = this.fields.length;
// compute field widths (-20 for first menu col + 10px for padding on each col and finally 16px for the scrollbar)
var fullWidth = self.el.width() - 20 - 10 * numFields - this.scrollbarDimensions.width;
var width = parseInt(Math.max(50, fullWidth / numFields));
var remainder = fullWidth - numFields * width;
_.each(this.fields, function(field, idx) {
// add the remainder to the first field width so we make up full col
if (idx == 0) {
field.set({width: width+remainder});
} else {
field.set({width: width});
}
});
var htmls = $.mustache(this.template, this.toTemplateJSON());
this.el.html(htmls);
this.model.currentDocuments.forEach(function(doc) {
@@ -195,6 +217,18 @@ my.Grid = Backbone.View.extend({
});
this.el.find('.recline-grid').toggleClass('no-hidden', (self.state.get('hiddenFields').length === 0));
return this;
},
// ### _scrollbarSize
//
// Measure width of a vertical scrollbar and height of a horizontal scrollbar.
//
// @return: { width: pixelWidth, height: pixelHeight }
_scrollbarSize: function() {
var $c = $("<div style='position:absolute; top:-10000px; left:-10000px; width:100px; height:100px; overflow:scroll;'></div>").appendTo("body");
var dim = { width: $c.width() - $c[0].clientWidth + 1, height: $c.height() - $c[0].clientHeight };
$c.remove();
return dim;
}
});
@@ -231,7 +265,7 @@ my.GridRow = Backbone.View.extend({
</div> \
</td> \
{{#cells}} \
<td data-field="{{field}}"> \
<td data-field="{{field}}" style="width: {{width}}px; max-width: {{width}}px;"> \
<div class="data-table-cell-content"> \
<a href="javascript:{}" class="data-table-cell-edit" title="Edit this cell">&nbsp;</a> \
<div class="data-table-cell-value">{{{value}}}</div> \
@@ -251,6 +285,7 @@ my.GridRow = Backbone.View.extend({
var cellData = this._fields.map(function(field) {
return {
field: field.id,
width: field.get('width'),
value: doc.getFieldValue(field)
};
});