Merge pull request #385 from aliounedia/master

[#384] add validator  to validate user input.
This commit is contained in:
Rufus Pollock
2014-01-22 00:54:13 -08:00
2 changed files with 172 additions and 27 deletions

View File

@@ -5,6 +5,40 @@ this.recline.View = this.recline.View || {};
(function($, my) { (function($, my) {
"use strict"; "use strict";
// Add new grid Control to display a new row add menu bouton
// It display a simple side-bar menu ,for user to add new
// row to grid
my.GridControl= Backbone.View.extend({
className: "recline-row-add",
// Template for row edit menu , change it if you don't love
template: '<h1><a href="#" class="recline-row-add btn">Add row</a></h1>',
initialize: function(options){
var self = this;
_.bindAll(this, 'render');
this.state = new recline.Model.ObjectState();
this.render();
},
render: function() {
var self = this;
this.$el.html(this.template)
},
events : {
"click .recline-row-add" : "addNewRow"
},
addNewRow : function(e){
e.preventDefault()
this.state.trigger("change")
}
}
);
// ## SlickGrid Dataset View // ## SlickGrid Dataset View
// //
// Provides a tabular view on a Dataset, based on SlickGrid. // Provides a tabular view on a Dataset, based on SlickGrid.
@@ -39,10 +73,14 @@ my.SlickGrid = Backbone.View.extend({
initialize: function(modelEtc) { initialize: function(modelEtc) {
var self = this; var self = this;
this.$el.addClass('recline-slickgrid'); this.$el.addClass('recline-slickgrid');
// Template for row delete menu , change it if you don't love
this.templates = {
"deleterow" : '<a href="#" class="recline-row-delete btn">X</a>'
}
_.bindAll(this, 'render', 'onRecordChanged'); _.bindAll(this, 'render', 'onRecordChanged');
this.listenTo(this.model.records, 'add remove reset', this.render); this.listenTo(this.model.records, 'add remove reset', this.render);
this.listenTo(this.model.records, 'change', this.onRecordChanged); this.listenTo(this.model.records, 'change', this.onRecordChanged);
var state = _.extend({ var state = _.extend({
hiddenColumns: [], hiddenColumns: [],
columnsOrder: [], columnsOrder: [],
@@ -55,29 +93,33 @@ my.SlickGrid = Backbone.View.extend({
); );
this.state = new recline.Model.ObjectState(state); this.state = new recline.Model.ObjectState(state);
this._slickHandler = new Slick.EventHandler(); this._slickHandler = new Slick.EventHandler();
},
events: { //add menu for new row , check if enableAddRow is set to true or not set
}, if(this.state.get("gridOptions")
&& this.state.get("gridOptions").enabledAddRow != undefined
&& this.state.get("gridOptions").enabledAddRow == true ){
this.editor = new my.GridControl()
this.elSidebar = this.editor.$el
this.listenTo(this.editor.state, 'change', function(){
this.model.records.add({})
});
}
},
onRecordChanged: function(record) { onRecordChanged: function(record) {
// Ignore if the grid is not yet drawn // Ignore if the grid is not yet drawn
if (!this.grid) { if (!this.grid) {
return; return;
} }
// Let's find the row corresponding to the index // Let's find the row corresponding to the index
var row_index = this.grid.getData().getModelRow( record ); var row_index = this.grid.getData().getModelRow( record );
this.grid.invalidateRow(row_index); this.grid.invalidateRow(row_index);
this.grid.getData().updateItem(record, row_index); this.grid.getData().updateItem(record, row_index);
this.grid.render(); this.grid.render();
}, },
render: function() {
render: function() {
var self = this; var self = this;
var options = _.extend({ var options = _.extend({
enableCellNavigation: true, enableCellNavigation: true,
enableColumnReorder: true, enableColumnReorder: true,
@@ -92,13 +134,41 @@ my.SlickGrid = Backbone.View.extend({
// plus this way we distinguish between rendering/formatting and computed value (so e.g. sort still works ...) // 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 // row = row index, cell = cell index, value = value, columnDef = column definition, dataContext = full row values
var formatter = function(row, cell, value, columnDef, dataContext) { var formatter = function(row, cell, value, columnDef, dataContext) {
var field = self.model.fields.get(columnDef.id); if(columnDef.id == "del"){
return self.templates.deleterow
}
var field = self.model.fields.get(columnDef.id);
if (field.renderer) { if (field.renderer) {
return field.renderer(value, field, dataContext); return field.renderer(value, field, dataContext);
} else { }else {
return value; return value
} }
}; };
// we need to be sure that user is entering a valid input , for exemple if
// field is date type and field.format ='YY-MM-DD', we should be sure that
// user enter a correct value
var validator = function(field){
return function(value){
if(field.type == "date" && isNaN(Date.parse(value))){
return {valid: false, msg: "A date is required , check field field-date-format"};
}else {
return {valid: true, msg :null }
}
}
};
//Add row delete support , check if enableDelRow is set to true or not set
if(this.state.get("gridOptions")
&& this.state.get("gridOptions").enabledDelRow != undefined
&& this.state.get("gridOptions").enabledDelRow == true ){
columns.push({
id: 'del',
name: 'del',
field: 'del',
sortable: true,
width: 80,
formatter: formatter,
validator:validator
})}
_.each(this.model.fields.toJSON(),function(field){ _.each(this.model.fields.toJSON(),function(field){
var column = { var column = {
id: field.id, id: field.id,
@@ -106,14 +176,13 @@ my.SlickGrid = Backbone.View.extend({
field: field.id, field: field.id,
sortable: true, sortable: true,
minWidth: 80, minWidth: 80,
formatter: formatter formatter: formatter,
validator:validator(field)
}; };
var widthInfo = _.find(self.state.get('columnsWidth'),function(c){return c.column === field.id;}); var widthInfo = _.find(self.state.get('columnsWidth'),function(c){return c.column === field.id;});
if (widthInfo){ if (widthInfo){
column.width = widthInfo.width; column.width = widthInfo.width;
} }
var editInfo = _.find(self.state.get('columnsEditor'),function(c){return c.column === field.id;}); var editInfo = _.find(self.state.get('columnsEditor'),function(c){return c.column === field.id;});
if (editInfo){ if (editInfo){
column.editor = editInfo.editor; column.editor = editInfo.editor;
@@ -138,12 +207,10 @@ my.SlickGrid = Backbone.View.extend({
} }
columns.push(column); columns.push(column);
}); });
// Restrict the visible columns // Restrict the visible columns
var visibleColumns = _.filter(columns, function(column) { var visibleColumns = _.filter(columns, function(column) {
return _.indexOf(self.state.get('hiddenColumns'), column.id) === -1; return _.indexOf(self.state.get('hiddenColumns'), column.id) === -1;
}); });
// Order them if there is ordering info on the state // Order them if there is ordering info on the state
if (this.state.get('columnsOrder') && this.state.get('columnsOrder').length > 0) { if (this.state.get('columnsOrder') && this.state.get('columnsOrder').length > 0) {
visibleColumns = visibleColumns.sort(function(a,b){ visibleColumns = visibleColumns.sort(function(a,b){
@@ -191,6 +258,7 @@ my.SlickGrid = Backbone.View.extend({
rows[i] = toRow(m); rows[i] = toRow(m);
models[i] = m; models[i] = m;
}; };
} }
var data = new RowSet(); var data = new RowSet();
@@ -200,7 +268,6 @@ my.SlickGrid = Backbone.View.extend({
}); });
this.grid = new Slick.Grid(this.el, data, visibleColumns, options); this.grid = new Slick.Grid(this.el, data, visibleColumns, options);
// Column sorting // Column sorting
var sortInfo = this.model.queryState.get('sort'); var sortInfo = this.model.queryState.get('sort');
if (sortInfo){ if (sortInfo){
@@ -236,16 +303,22 @@ my.SlickGrid = Backbone.View.extend({
this._slickHandler.subscribe(this.grid.onCellChange, function (e, args) { this._slickHandler.subscribe(this.grid.onCellChange, function (e, args) {
// We need to change the model associated value // We need to change the model associated value
//
var grid = args.grid; var grid = args.grid;
var model = data.getModel(args.row); var model = data.getModel(args.row);
var field = grid.getColumns()[args.cell].id; var field = grid.getColumns()[args.cell].id;
var v = {}; var v = {};
v[field] = args.item[field]; v[field] = args.item[field];
model.set(v); model.set(v);
}); });
this._slickHandler.subscribe(this.grid.onClick,function(e, args){
if (args.cell == 0){
// We need to delete the associated model
var model = data.getModel(args.row);
model.destroy()
}
}) ;
var columnpicker = new Slick.Controls.ColumnPicker(columns, this.grid, var columnpicker = new Slick.Controls.ColumnPicker(columns, this.grid,
_.extend(options,{state:this.state})); _.extend(options,{state:this.state}));
if (self.visible){ if (self.visible){
@@ -402,3 +475,4 @@ my.SlickGrid = Backbone.View.extend({
// Slick.Controls.ColumnPicker // Slick.Controls.ColumnPicker
$.extend(true, window, { Slick:{ Controls:{ ColumnPicker:SlickColumnPicker }}}); $.extend(true, window, { Slick:{ Controls:{ ColumnPicker:SlickColumnPicker }}});
})(jQuery); })(jQuery);

View File

@@ -103,6 +103,77 @@ test('editable', function () {
view.remove(); view.remove();
}); });
test('delete-row' , function(){
var dataset = Fixture.getDataset();
var view = new recline.View.SlickGrid({
model: dataset,
state: {
hiddenColumns:['x','lat','title'],
columnsOrder:['lon','id','z','date', 'y', 'country'],
columnsWidth:[
{column:'id',width: 250}
],
gridOptions: {editable: true , "enabledDelRow":true},
columnsEditor: [{column: 'country', editor: Slick.Editors.Text}]
}
});
$('.fixtures .test-datatable').append(view.el);
view.render();
view.show();
old_length = dataset.records.length
dataset.records.on('remove', function(record){
equal(dataset.records.length, old_length -1 );
});
// Be sure a cell change triggers a change of the model
e = new Slick.EventData();
view.grid.onClick.notify({
row: 1,
cell: 0,
grid: view.grid
}, e, view.grid);
view.remove();
});
test('add-row' , function(){
//To test adding row on slickgrid , we add some menu GridControl
//I am based on the FlotControl in flot wiewer , to add a similary
//to the sclickgrid , The GridControl add a bouton menu
//one the .side-bar place , which will allow to add a row to
//the grid on-click
var dataset = Fixture.getDataset();
var view = new recline.View.SlickGrid({
model: dataset,
state: {
hiddenColumns:['x','lat','title'],
columnsOrder:['lon','id','z','date', 'y', 'country'],
columnsWidth:[
{column:'id',width: 250}
],
gridOptions: {editable: true , "enabledAddRow":true},
columnsEditor: [{column: 'country', editor: Slick.Editors.Text}]
}
});
// view will auto render ...
assertPresent('.recline-row-add', view.elSidebar);
// see recline.SlickGrid.GridControl widget
//view.render()
old_length = dataset.records.length
dataset.records.on('add',function(record){
equal(dataset.records.length ,old_length + 1 )
});
view.elSidebar.find('.recline-row-add').click();
});
test('update', function() { test('update', function() {
var dataset = Fixture.getDataset(); var dataset = Fixture.getDataset();
var view = new recline.View.SlickGrid({ var view = new recline.View.SlickGrid({