New setup supports: * Column hiding * Column reordering * Column sorting * Column resizing * Fit columns to the div width All these options are stored on the view state and applied when initializing the view if necessary. Now also utilize slickgrid view as default grid view.
298 lines
8.7 KiB
JavaScript
298 lines
8.7 KiB
JavaScript
/*jshint multistr:true */
|
|
|
|
this.recline = this.recline || {};
|
|
this.recline.View = this.recline.View || {};
|
|
|
|
(function($, my) {
|
|
// ## SlickGrid Dataset View
|
|
//
|
|
// Provides a tabular view on a Dataset, based on SlickGrid.
|
|
//
|
|
// https://github.com/mleibman/SlickGrid
|
|
//
|
|
// Initialize it with a `recline.Model.Dataset`.
|
|
my.SlickGrid = Backbone.View.extend({
|
|
tagName: "div",
|
|
className: "recline-slickgrid",
|
|
|
|
initialize: function(modelEtc) {
|
|
var self = this;
|
|
this.el = $(this.el);
|
|
_.bindAll(this, 'render');
|
|
this.model.currentDocuments.bind('add', this.render);
|
|
this.model.currentDocuments.bind('reset', this.render);
|
|
this.model.currentDocuments.bind('remove', this.render);
|
|
|
|
var state = _.extend({
|
|
hiddenColumns: [],
|
|
columnsOrder: [],
|
|
columnsSort: {},
|
|
columnsWidth: [],
|
|
fitColumns: false
|
|
}, modelEtc.state
|
|
);
|
|
this.state = new recline.Model.ObjectState(state);
|
|
|
|
this.bind('view:show',function(){
|
|
// If the div is hidden, SlickGrid will calculate wrongly some
|
|
// sizes so we must render it explicitly when the view is visible
|
|
if (!self.rendered){
|
|
if (!self.grid){
|
|
self.render();
|
|
}
|
|
self.grid.init();
|
|
self.rendered = true;
|
|
}
|
|
self.visible = true;
|
|
});
|
|
this.bind('view:hide',function(){
|
|
self.visible = false;
|
|
});
|
|
|
|
},
|
|
|
|
events: {
|
|
},
|
|
|
|
render: function() {
|
|
var self = this;
|
|
this.el = $(this.el);
|
|
|
|
var options = {
|
|
enableCellNavigation: true,
|
|
enableColumnReorder: true,
|
|
explicitInitialization: true,
|
|
syncColumnCellResize: true,
|
|
forceFitColumns: this.state.get('fitColumns')
|
|
};
|
|
|
|
// We need all columns, even the hidden ones, to show on the column picker
|
|
var columns = [];
|
|
_.each(this.model.fields.toJSON(),function(field){
|
|
var column = {id:field['id'],
|
|
name:field['label'],
|
|
field:field['id'],
|
|
sortable: true,
|
|
minWidth: 80};
|
|
|
|
var widthInfo = _.find(self.state.get('columnsWidth'),function(c){return c.column == field.id});
|
|
if (widthInfo){
|
|
column['width'] = widthInfo.width;
|
|
}
|
|
|
|
columns.push(column);
|
|
});
|
|
|
|
// Restrict the visible columns
|
|
var visibleColumns = columns.filter(function(column) {
|
|
return _.indexOf(self.state.get('hiddenColumns'), column.id) == -1;
|
|
});
|
|
|
|
// Order them if there is ordering info on the state
|
|
if (this.state.get('columnsOrder')){
|
|
visibleColumns = visibleColumns.sort(function(a,b){
|
|
return _.indexOf(self.state.get('columnsOrder'),a.id) > _.indexOf(self.state.get('columnsOrder'),b.id);
|
|
});
|
|
columns = columns.sort(function(a,b){
|
|
return _.indexOf(self.state.get('columnsOrder'),a.id) > _.indexOf(self.state.get('columnsOrder'),b.id);
|
|
});
|
|
}
|
|
|
|
// Move hidden columns to the end, so they appear at the bottom of the
|
|
// column picker
|
|
var tempHiddenColumns = [];
|
|
for (var i = columns.length -1; i >= 0; i--){
|
|
if (_.indexOf(_.pluck(visibleColumns,'id'),columns[i].id) == -1){
|
|
tempHiddenColumns.push(columns.splice(i,1)[0]);
|
|
}
|
|
}
|
|
columns = columns.concat(tempHiddenColumns);
|
|
|
|
|
|
var data = this.model.currentDocuments.toJSON();
|
|
|
|
this.grid = new Slick.Grid(this.el, data, visibleColumns, options);
|
|
|
|
// Column sorting
|
|
var gridSorter = function(field, ascending, grid, data){
|
|
|
|
data.sort(function(a, b){
|
|
var result =
|
|
a[field] > b[field] ? 1 :
|
|
a[field] < b[field] ? -1 :
|
|
0
|
|
;
|
|
return ascending ? result : -result;
|
|
});
|
|
|
|
grid.setData(data);
|
|
grid.updateRowCount();
|
|
grid.render();
|
|
}
|
|
|
|
var sortInfo = this.state.get('columnsSort');
|
|
if (sortInfo){
|
|
var sortAsc = !(sortInfo['direction'] == 'desc');
|
|
gridSorter(sortInfo.column, sortAsc, self.grid, data);
|
|
this.grid.setSortColumn(sortInfo.column, sortAsc);
|
|
}
|
|
|
|
this.grid.onSort.subscribe(function(e, args){
|
|
gridSorter(args.sortCol.field,args.sortAsc,self.grid,data);
|
|
self.state.set({columnsSort:{
|
|
column:args.sortCol,
|
|
direction: (args.sortAsc) ? 'asc':'desc'
|
|
}});
|
|
});
|
|
|
|
this.grid.onColumnsReordered.subscribe(function(e, args){
|
|
self.state.set({columnsOrder: _.pluck(self.grid.getColumns(),'id')});
|
|
});
|
|
|
|
this.grid.onColumnsResized.subscribe(function(e, args){
|
|
var columns = args.grid.getColumns();
|
|
var defaultColumnWidth = args.grid.getOptions().defaultColumnWidth;
|
|
var columnsWidth = [];
|
|
_.each(columns,function(column){
|
|
if (column.width != defaultColumnWidth){
|
|
columnsWidth.push({column:column.id,width:column.width});
|
|
}
|
|
});
|
|
self.state.set({columnsWidth:columnsWidth});
|
|
});
|
|
|
|
var columnpicker = new Slick.Controls.ColumnPicker(columns, this.grid,
|
|
_.extend(options,{state:this.state}));
|
|
|
|
if (self.visible){
|
|
self.grid.init();
|
|
self.rendered = true;
|
|
} else {
|
|
// Defer rendering until the view is visible
|
|
self.rendered = false;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
});
|
|
|
|
})(jQuery, recline.View);
|
|
|
|
/*
|
|
* Context menu for the column picker, adapted from
|
|
* http://mleibman.github.com/SlickGrid/examples/example-grouping
|
|
*
|
|
*/
|
|
(function ($) {
|
|
function SlickColumnPicker(columns, grid, options) {
|
|
var $menu;
|
|
var columnCheckboxes;
|
|
|
|
var defaults = {
|
|
fadeSpeed:250
|
|
};
|
|
|
|
function init() {
|
|
grid.onHeaderContextMenu.subscribe(handleHeaderContextMenu);
|
|
options = $.extend({}, defaults, options);
|
|
|
|
$menu = $('<ul class="dropdown-menu slick-contextmenu" style="display:none;position:absolute;z-index:20;" />').appendTo(document.body);
|
|
|
|
$menu.bind('mouseleave', function (e) {
|
|
$(this).fadeOut(options.fadeSpeed)
|
|
});
|
|
$menu.bind('click', updateColumn);
|
|
|
|
}
|
|
|
|
function handleHeaderContextMenu(e, args) {
|
|
e.preventDefault();
|
|
$menu.empty();
|
|
columnCheckboxes = [];
|
|
|
|
var $li, $input;
|
|
for (var i = 0; i < columns.length; i++) {
|
|
$li = $('<li />').appendTo($menu);
|
|
$input = $('<input type="checkbox" />').data('column-id', columns[i].id).attr('id','slick-column-vis-'+columns[i].id);
|
|
columnCheckboxes.push($input);
|
|
|
|
if (grid.getColumnIndex(columns[i].id) != null) {
|
|
$input.attr('checked', 'checked');
|
|
}
|
|
$input.appendTo($li);
|
|
$('<label />')
|
|
.text(columns[i].name)
|
|
.attr('for','slick-column-vis-'+columns[i].id)
|
|
.appendTo($li);
|
|
}
|
|
$('<li/>').addClass('divider').appendTo($menu);
|
|
$li = $('<li />').data('option', 'autoresize').appendTo($menu);
|
|
$input = $('<input type="checkbox" />').data('option', 'autoresize').attr('id','slick-option-autoresize');
|
|
$input.appendTo($li);
|
|
$('<label />')
|
|
.text('Force fit columns')
|
|
.attr('for','slick-option-autoresize')
|
|
.appendTo($li);
|
|
if (grid.getOptions().forceFitColumns) {
|
|
$input.attr('checked', 'checked');
|
|
}
|
|
|
|
$menu.css('top', e.pageY - 10)
|
|
.css('left', e.pageX - 10)
|
|
.fadeIn(options.fadeSpeed);
|
|
}
|
|
|
|
function updateColumn(e) {
|
|
if ($(e.target).data('option') == 'autoresize') {
|
|
var checked;
|
|
if ($(e.target).is('li')){
|
|
var checkbox = $(e.target).find('input').first();
|
|
checked = !checkbox.is(':checked');
|
|
checkbox.attr('checked',checked);
|
|
} else {
|
|
checked = e.target.checked;
|
|
}
|
|
|
|
if (checked) {
|
|
grid.setOptions({forceFitColumns:true});
|
|
grid.autosizeColumns();
|
|
} else {
|
|
grid.setOptions({forceFitColumns:false});
|
|
}
|
|
options.state.set({fitColumns:checked});
|
|
return;
|
|
}
|
|
|
|
if (($(e.target).is('li') && !$(e.target).hasClass('divider')) ||
|
|
$(e.target).is('input')) {
|
|
if ($(e.target).is('li')){
|
|
var checkbox = $(e.target).find('input').first();
|
|
checkbox.attr('checked',!checkbox.is(':checked'));
|
|
}
|
|
var visibleColumns = [];
|
|
var hiddenColumnsIds = [];
|
|
$.each(columnCheckboxes, function (i, e) {
|
|
if ($(this).is(':checked')) {
|
|
visibleColumns.push(columns[i]);
|
|
} else {
|
|
hiddenColumnsIds.push(columns[i].id);
|
|
}
|
|
});
|
|
|
|
|
|
if (!visibleColumns.length) {
|
|
$(e.target).attr('checked', 'checked');
|
|
return;
|
|
}
|
|
|
|
grid.setColumns(visibleColumns);
|
|
options.state.set({hiddenColumns:hiddenColumnsIds});
|
|
}
|
|
}
|
|
init();
|
|
}
|
|
|
|
// Slick.Controls.ColumnPicker
|
|
$.extend(true, window, { Slick:{ Controls:{ ColumnPicker:SlickColumnPicker }}});
|
|
})(jQuery);
|