app/assets/javascripts/grid.js
var jobsworth = jobsworth || {};
jobsworth.Grid = (function ($) {
var columns = [
{
id: 'read',
name: "<span class='unread_icon'/>",
field: 'read',
resizable: false,
sortable: true,
formatter: UnreadMarkFormatter,
width: 16
},
{id: 'id', name: 'id', field: 'id', sortable: true},
{id: 'summary', name: 'summary', field: 'summary', formatter: HtmlFormatter, width: 300},
{id: 'client', name: 'client', field: 'client', sortable: true, formatter: HtmlFormatter},
{id: 'milestone', name: 'milestone', field: 'milestone', sortable: true, formatter: HtmlFormatter},
{id: 'due', name: 'target date', field: 'due', sortable: true, formatter: HtmlFormatter},
{id: 'time', name: 'time', field: 'time', sortable: true, formatter: DurationFormatter},
{id: 'assigned', name: 'assigned', field: 'assigned', sortable: true},
{id: 'resolution', name: 'resolution', field: 'resolution', sortable: true},
{id: 'estimate_date', name: 'Forecast date', field: 'estimate_date', sortable: true, formatter: HtmlFormatter},
{id: 'updated_at', name: 'last comment date', field: 'updated_at', sortable: true, formatter: TimeFormatter}
];
function Grid(options) {
this.options = options;
this.init();
}
/* formatters for SlickGrid */
function UnreadMarkFormatter(row, cell, value) {
return value == "f" ? "<span class='unread_icon'/>" : "";
}
// fix slickgrid displaying html in cell
function DurationFormatter(row, cell, value, _columnDef, dataContext) {
if (value == 0) {
return "";
} else {
if (dataContext.is_default == true) {
return "<span class='defaultValue'>" + Math.round(value / 6) / 10 + "hr (default)</span>";
} else {
return Math.round(value / 6) / 10 + "hr";
}
}
}
function HtmlFormatter(row, cell, value) {
return value;
}
function TimeFormatter(row, cell, value) {
if (value) {
return $.timeago(value);
}
}
/* end of formatters */
Grid.prototype.init = function () {
var self = this;
$.getJSON("/companies/properties", function (data) {
for (var index in data) {
var property = data[index];
columns.push({
id: property.name.toLowerCase(),
name: property.name.toLowerCase(),
field: property.name.toLowerCase(),
sortable: true,
formatter: HtmlFormatter
});
}
$.getJSON("/tasks?format=json", function (rows) {
self.createGrid(rows);
})
})
};
Grid.prototype.reload = function () {
var self = this;
$.getJSON("/tasks?format=json", function (rows) {
self.dataView.setItems(rows);
self.grid.invalidate();
self.grid.render();
})
};
Grid.prototype.bind = function () {
var self = this;
$("#groupBy select").change(function () {
var value = $(this).val();
store.set("grid.groupBy", value);
for (var index in columns) {
if (columns[index].id == value) {
self.groupBy(columns[index]);
return;
}
}
self.groupBy(null);
});
$(".groupByOption").live('click', function () {
var value = $(this).text().toLowerCase();
//For adding tick mark
$(".groupByTick").removeClass("groupByTick");
$(".groupByOption").each(function () {
if ($(this).text().toLowerCase() == value) {
$(this).addClass("groupByTick");
}
});
if (value == "not grouped") {
value = "clear";
}
store.set("grid.groupBy", value);
for (var index in columns) {
if (columns[index].id == value) {
self.groupBy(columns[index]);
return;
}
}
self.groupBy(null);
});
this.grid.onClick.subscribe(function (e) {
var cell = self.grid.getCellFromEvent(e);
var task = self.grid.getDataItem(cell.row);
// mark task as read
if (task.read == "f") {
task.read = "t";
self.dataView.updateItem(task.id, task);
}
new jobsworth.Task(task.id);
});
this.grid.onSort.subscribe(function (e, args) {
self.onSort(args);
});
this.dataView.onRowCountChanged.subscribe(function (e) {
self.grid.updateRowCount();
self.grid.render();
});
this.dataView.onRowsChanged.subscribe(function (e, args) {
self.grid.invalidateRows(args.rows);
self.grid.render();
});
this.grid.onColumnsReordered.subscribe(function (e) {
store.set('grid.Columns', self.grid.getColumns());
});
this.grid.onColumnsResized.subscribe(function (e) {
store.set('grid.Columns', self.grid.getColumns());
});
$(window).resize(function () {
self.grid.resizeCanvas();
});
};
Grid.prototype.createGrid = function (rows) {
var self = this;
var options = {
enableCellNavigation: true,
enableColumnReorder: true,
multiColumnSort: true,
forceFitColumns: true
};
var groupItemMetadataProvider = new Slick.Data.GroupItemMetadataProvider();
this.dataView = new Slick.Data.DataView({
groupItemMetadataProvider: groupItemMetadataProvider,
inlineFilters: true
});
// highlight unread line
this.dataView.getItemMetadata = (function (original_provider) {
return function (row) {
var item = this.getItem(row),
ret = original_provider(row);
if (item) {
ret = ret || {};
if (item.read == "f") {
ret.cssClasses = (ret.cssClasses || '') + ' unread';
} else {
ret.cssClasses = (ret.cssClasses || '') + ' read';
}
// highlight the top next task
if (item.is_top_next_task) {
ret.cssClasses = (ret.cssClasses || '') + ' top-next-task';
}
}
return ret;
}
})(this.dataView.getItemMetadata);
this.grid = new Slick.Grid(this.options.el, this.dataView, columns, options);
this.grid.setSelectionModel(new Slick.RowSelectionModel());
this.grid.registerPlugin(groupItemMetadataProvider);
var columnpicker = new jobsworth.grids.ColumnPicker(columns, this.grid, options);
// this line must be called before the lines below
this.bind();
// resize grid
if (store.get('grid.height')) {
$(this.options.el).height(store.get('grid.height'));
}
$(this.options.el).resizable({
handles: 's',
stop: function (event, ui) {
store.set("grid.height", ui.size.height);
}
});
this.dataView.beginUpdate();
this.dataView.setItems(rows);
this.dataView.endUpdate();
this.grid.autosizeColumns();
// sort rows
if (store.get('sortArgs')) {
var args = store.get('sortArgs');
var col = args.sortCols[0];
if (col.sortCol.id != 'id') {
this.grid.setSortColumn(col.sortCol.id, col.sortAsc);
self.onSort(args);
}
}
// group rows
if (store.get('grid.groupBy')) {
var grouped_by = store.get('grid.groupBy');
if (grouped_by == "clear") {
grouped_by = "not grouped";
}
$('.groupByOption').each(function () {
var value = $(this).text().toLowerCase();
if (value == grouped_by) {
$(this).trigger('click');
}
});
}
// select columns
if (store.get('grid.Columns')) {
var visibleColumns = [];
var cols = store.get('grid.Columns');
for (var i in cols) {
for (var j in columns) {
if (cols[i].name == columns[j].name) {
columns[j].width = cols[i].width;
visibleColumns.push(columns[j]);
}
}
}
this.grid.setColumns(visibleColumns);
}
};
Grid.prototype.groupBy = function (column) {
if (!column) {
this.dataView.groupBy(null);
return;
}
this.dataView.groupBy(
column.field,
function (g) {
var total = 0;
for (var i in g.rows) {
total = total + g.rows[i].time;
}
var hours = Math.round(total / 6) / 10 + "hr";
return column.name + ": " + g.value + " <span class='itemCount'>(" + g.count + " items, " + hours + ")</span>";
},
function (a, b) {
return a.value > b.value;
}
);
};
Grid.prototype.onSort = function (args) {
var cols = args.sortCols;
this.grid.getData().sort(function (dataRow1, dataRow2) {
for (var i = 0, l = cols.length; i < l; i++) {
var field = cols[i].sortCol.field;
var sign = cols[i].sortAsc ? 1 : -1;
var value1 = dataRow1[field], value2 = dataRow2[field];
var result = (value1 == value2 ? 0 : (value1 > value2 ? 1 : -1)) * sign;
if (result != 0) {
return result;
}
}
return 0;
});
store.set('sortArgs', args);
this.grid.invalidate();
this.grid.render();
};
return Grid;
})(jQuery);