[#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:
56
css/grid.css
56
css/grid.css
@@ -2,20 +2,22 @@
|
|||||||
* (Data) Grid
|
* (Data) Grid
|
||||||
*********************************************************/
|
*********************************************************/
|
||||||
|
|
||||||
|
table.recline-grid {
|
||||||
|
table-layout: fixed;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.recline-grid .btn-group .dropdown-toggle {
|
.recline-grid .btn-group .dropdown-toggle {
|
||||||
padding: 1px 3px;
|
padding: 1px 3px;
|
||||||
line-height: auto;
|
line-height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.recline-grid {
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.recline-grid td, .recline-grid th {
|
.recline-grid td, .recline-grid th {
|
||||||
border-left: 1px solid #ccc;
|
border-left: 1px solid #ccc;
|
||||||
padding: 3px 4px;
|
padding: 3px 4px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
word-wrap: break-word;
|
||||||
|
white-space: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.recline-grid td {
|
.recline-grid td {
|
||||||
@@ -26,6 +28,14 @@
|
|||||||
width: 20px;
|
width: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.recline-grid tbody tr:last-child {
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recline-grid tbody td:last-child {
|
||||||
|
border-right: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
/* direct borrowing from twitter buttons */
|
/* direct borrowing from twitter buttons */
|
||||||
.recline-grid th,
|
.recline-grid th,
|
||||||
.transform-column-view .expression-preview-table-wrapper th
|
.transform-column-view .expression-preview-table-wrapper th
|
||||||
@@ -53,6 +63,42 @@
|
|||||||
transition: 0.1s linear all;
|
transition: 0.1s linear all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**********************************************************
|
||||||
|
* Fixed Header - http://www.imaputz.com/cssStuff/bigFourVersion.html
|
||||||
|
*********************************************************/
|
||||||
|
|
||||||
|
div.table-container {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset overflow value to hidden for all non-IE browsers. */
|
||||||
|
html>body div.table-container {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set table header to a fixed position. WinIE 6.x only */
|
||||||
|
/* In WinIE 6.x, any element with a position property set to relative and is a child of */
|
||||||
|
/* an element that has an overflow property set, the relative value translates into fixed. */
|
||||||
|
/* Ex: parent element DIV with a class of table-container has an overflow property set to auto */
|
||||||
|
thead.fixed-header tr {
|
||||||
|
position: relative
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set THEAD element to have block level attributes. All other non-IE browsers */
|
||||||
|
/* this enables overflow to work on TBODY element. All other non-IE, non-Mozilla browsers */
|
||||||
|
html>body thead.fixed-header tr {
|
||||||
|
display: block
|
||||||
|
}
|
||||||
|
|
||||||
|
/* define the table content to be scrollable */
|
||||||
|
/* set TBODY element to have block level attributes. All other non-IE browsers */
|
||||||
|
/* this enables overflow to work on TBODY element. All other non-IE, non-Mozilla browsers */
|
||||||
|
/* induced side effect is that child TDs no longer accept width: auto */
|
||||||
|
tbody.scrollContent {
|
||||||
|
display: block;
|
||||||
|
max-height: 500px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
/**********************************************************
|
/**********************************************************
|
||||||
* Data Table Menus
|
* Data Table Menus
|
||||||
|
|||||||
@@ -130,8 +130,9 @@ my.Grid = Backbone.View.extend({
|
|||||||
// ======================================================
|
// ======================================================
|
||||||
// #### Templating
|
// #### Templating
|
||||||
template: ' \
|
template: ' \
|
||||||
|
<div class="table-container"> \
|
||||||
<table class="recline-grid table-striped table-condensed" cellspacing="0"> \
|
<table class="recline-grid table-striped table-condensed" cellspacing="0"> \
|
||||||
<thead> \
|
<thead class="fixed-header"> \
|
||||||
<tr> \
|
<tr> \
|
||||||
{{#notEmpty}} \
|
{{#notEmpty}} \
|
||||||
<th class="column-header"> \
|
<th class="column-header"> \
|
||||||
@@ -144,7 +145,7 @@ my.Grid = Backbone.View.extend({
|
|||||||
</th> \
|
</th> \
|
||||||
{{/notEmpty}} \
|
{{/notEmpty}} \
|
||||||
{{#fields}} \
|
{{#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"> \
|
<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> \
|
<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"> \
|
<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> \
|
<span class="column-header-name">{{label}}</span> \
|
||||||
</th> \
|
</th> \
|
||||||
{{/fields}} \
|
{{/fields}} \
|
||||||
|
<th class="last-header" style="width: {{lastHeaderWidth}}px; padding: 0; margin: 0;"></th> \
|
||||||
</tr> \
|
</tr> \
|
||||||
</thead> \
|
</thead> \
|
||||||
<tbody></tbody> \
|
<tbody class="scrollContent"></tbody> \
|
||||||
</table> \
|
</table> \
|
||||||
|
</div> \
|
||||||
',
|
',
|
||||||
|
|
||||||
toTemplateJSON: function() {
|
toTemplateJSON: function() {
|
||||||
|
var self = this;
|
||||||
var modelData = this.model.toJSON();
|
var modelData = this.model.toJSON();
|
||||||
modelData.notEmpty = ( this.fields.length > 0 );
|
modelData.notEmpty = ( this.fields.length > 0 );
|
||||||
// TODO: move this sort of thing into a toTemplateJSON method on Dataset?
|
// 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;
|
return modelData;
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
@@ -181,6 +189,20 @@ my.Grid = Backbone.View.extend({
|
|||||||
this.fields = this.model.fields.filter(function(field) {
|
this.fields = this.model.fields.filter(function(field) {
|
||||||
return _.indexOf(self.state.get('hiddenFields'), field.id) == -1;
|
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());
|
var htmls = $.mustache(this.template, this.toTemplateJSON());
|
||||||
this.el.html(htmls);
|
this.el.html(htmls);
|
||||||
this.model.currentDocuments.forEach(function(doc) {
|
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));
|
this.el.find('.recline-grid').toggleClass('no-hidden', (self.state.get('hiddenFields').length === 0));
|
||||||
return this;
|
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> \
|
</div> \
|
||||||
</td> \
|
</td> \
|
||||||
{{#cells}} \
|
{{#cells}} \
|
||||||
<td data-field="{{field}}"> \
|
<td data-field="{{field}}" style="width: {{width}}px; max-width: {{width}}px;"> \
|
||||||
<div class="data-table-cell-content"> \
|
<div class="data-table-cell-content"> \
|
||||||
<a href="javascript:{}" class="data-table-cell-edit" title="Edit this cell"> </a> \
|
<a href="javascript:{}" class="data-table-cell-edit" title="Edit this cell"> </a> \
|
||||||
<div class="data-table-cell-value">{{{value}}}</div> \
|
<div class="data-table-cell-value">{{{value}}}</div> \
|
||||||
@@ -251,6 +285,7 @@ my.GridRow = Backbone.View.extend({
|
|||||||
var cellData = this._fields.map(function(field) {
|
var cellData = this._fields.map(function(field) {
|
||||||
return {
|
return {
|
||||||
field: field.id,
|
field: field.id,
|
||||||
|
width: field.get('width'),
|
||||||
value: doc.getFieldValue(field)
|
value: doc.getFieldValue(field)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user