/*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`. // // NB: you need an explicit height on the element for slickgrid to work my.SlickGrid = Backbone.View.extend({ initialize: function(modelEtc) { var self = this; this.el = $(this.el); this.el.addClass('recline-slickgrid'); _.bindAll(this, 'render'); this.model.records.bind('add', this.render); this.model.records.bind('reset', this.render); this.model.records.bind('remove', this.render); var state = _.extend({ hiddenColumns: [], columnsOrder: [], columnsSort: {}, columnsWidth: [], fitColumns: false }, modelEtc.state ); this.state = new recline.Model.ObjectState(state); }, events: { }, render: function() { var self = this; 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 = []; // custom formatter as default one escapes html // plus this way we distinguish between rendering/formatting and computed value (so e.g. sort still works ...) // row = row index, cell = cell index, value = value, columnDef = column definition, dataContext = full row values var formatter = function(row, cell, value, columnDef, dataContext) { var field = self.model.fields.get(columnDef.id); if (field.renderer) { return field.renderer(value, field, dataContext); } else { return value; } } _.each(this.model.fields.toJSON(),function(field){ var column = { id:field['id'], name:field['label'], field:field['id'], sortable: true, minWidth: 80, formatter: formatter }; 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) ? 1 : -1; }); columns = columns.sort(function(a,b){ return _.indexOf(self.state.get('columnsOrder'),a.id) > _.indexOf(self.state.get('columnsOrder'),b.id) ? 1 : -1; }); } // 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.records.each(function(doc){ var row = {}; self.model.fields.each(function(field){ row[field.id] = doc.getFieldValueUnrendered(field); }); data.push(row); }); this.grid = new Slick.Grid(this.el, data, visibleColumns, options); // Column sorting var sortInfo = this.model.queryState.get('sort'); if (sortInfo){ var column = _.keys(sortInfo[0])[0]; var sortAsc = !(sortInfo[0][column].order == 'desc'); this.grid.setSortColumn(column, sortAsc); } this.grid.onSort.subscribe(function(e, args){ var order = (args.sortAsc) ? 'asc':'desc'; var sort = [{}]; sort[0][args.sortCol.field] = {order: order}; self.model.query({sort: sort}); }); 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; }, 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 (!this.rendered){ if (!this.grid){ this.render(); } this.grid.init(); this.rendered = true; } this.visible = true; }, hide: function() { this.visible = false; } }); })(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 = $('