/* * Ext JS Library 2.0 Copyright(c) 2006-2007, Ext JS, LLC. licensing@extjs.com * * http://extjs.com/license */ /** * @class Ext.grid.PropertyRecord A specific {@link Ext.data.Record} type that * represents a name/value pair and is made to work with the * {@link Ext.grid.PropertyGrid}. Typically, PropertyRecords do not need * to be created directly as they can be created implicitly by simply * using the appropriate data configs either via the * {@link Ext.grid.PropertyGrid#source} config property or by calling * {@link Ext.grid.PropertyGrid#setSource}. However, if the need arises, * these records can also be created explicitly as shwon below. Example * usage: * *
* var rec = new Ext.grid.PropertyRecord({
* name : 'Birthday',
* value : new Date(Date.parse('05/26/1972'))
* });
* // Add record to an already populated grid
* grid.store.addSorted(rec);
*
*
* @constructor
* @param {Object}
* config A data object in the format: {name: [name], value:
* [value]}. The specified value's type will be read automatically by
* the grid to determine the type of editor to use when displaying
* it.
*/
Ext.grid.PropertyRecord = Ext.data.Record.create([{
name : 'name',
type : 'string'
}, 'value']);
/**
* @class Ext.grid.PropertyStore
* @extends Ext.util.Observable A custom wrapper for the
* {@link Ext.grid.PropertyGrid}'s {@link Ext.data.Store}. This class
* handles the mapping between the custom data source objects supported
* by the grid and the {@link Ext.grid.PropertyRecord} format required
* for compatibility with the underlying store. Generally this class
* should not need to be used directly -- the grid's data should be
* accessed from the underlying store via the {@link #store} property.
* @constructor
* @param {Ext.grid.Grid}
* grid The grid this store will be bound to
* @param {Object}
* source The source data config object
*/
Ext.grid.PropertyStore = function(grid, source) {
this.grid = grid;
this.store = new Ext.data.Store({
recordType : Ext.grid.PropertyRecord
});
this.store.on('update', this.onUpdate, this);
if (source) {
this.setSource(source);
}
Ext.grid.PropertyStore.superclass.constructor.call(this);
};
Ext.extend(Ext.grid.PropertyStore, Ext.util.Observable, {
// protected - should only be called by the grid. Use grid.setSource
// instead.
setSource : function(o) {
this.source = o;
this.store.removeAll();
var data = [];
for (var k in o) {
if (this.isEditableValue(o[k])) {
data.push(new Ext.grid.PropertyRecord({
name : k,
value : o[k]
}, k));
}
}
this.store.loadRecords({
records : data
}, {}, true);
},
// private
onUpdate : function(ds, record, type) {
if (type == Ext.data.Record.EDIT) {
var v = record.data['value'];
var oldValue = record.modified['value'];
if (this.grid.fireEvent('beforepropertychange',
this.source, record.id, v, oldValue) !== false) {
this.source[record.id] = v;
record.commit();
this.grid.fireEvent('propertychange', this.source,
record.id, v, oldValue);
} else {
record.reject();
}
}
},
// private
getProperty : function(row) {
return this.store.getAt(row);
},
// private
isEditableValue : function(val) {
if (val && val instanceof Date) {
return true;
} else if (typeof val == 'object' || typeof val == 'function') {
return false;
}
return true;
},
// private
setValue : function(prop, value) {
this.source[prop] = value;
this.store.getById(prop).set('value', value);
},
// protected - should only be called by the grid. Use grid.getSource
// instead.
getSource : function() {
return this.source;
}
});
/**
* @class Ext.grid.PropertyColumnModel
* @extends Ext.grid.ColumnModel A custom column model for the
* {@link Ext.grid.PropertyGrid}. Generally it should not need to be
* used directly.
* @constructor
* @param {Ext.grid.Grid}
* grid The grid this store will be bound to
* @param {Object}
* source The source data config object
*/
Ext.grid.PropertyColumnModel = function(grid, store) {
this.grid = grid;
var g = Ext.grid;
g.PropertyColumnModel.superclass.constructor.call(this, [{
header : this.nameText,
width : 50,
sortable : true,
dataIndex : 'name',
id : 'name'
}, {
header : this.valueText,
width : 50,
resizable : false,
dataIndex : 'value',
id : 'value'
}]);
this.store = store;
this.bselect = Ext.DomHelper.append(document.body, {
tag : 'select',
cls : 'x-grid-editor x-hide-display',
children : [{
tag : 'option',
value : 'true',
html : 'true'
}, {
tag : 'option',
value : 'false',
html : 'false'
}]
});
var f = Ext.form;
var bfield = new f.Field({
el : this.bselect,
bselect : this.bselect,
autoShow : true,
getValue : function() {
return this.bselect.value == 'true';
}
});
this.editors = {
'date' : new g.GridEditor(new f.DateField({
selectOnFocus : true
})),
'string' : new g.GridEditor(new f.TextField({
selectOnFocus : true
})),
'number' : new g.GridEditor(new f.NumberField({
selectOnFocus : true,
style : 'text-align:left;'
})),
'boolean' : new g.GridEditor(bfield)
};
this.renderCellDelegate = this.renderCell.createDelegate(this);
this.renderPropDelegate = this.renderProp.createDelegate(this);
};
Ext.extend(Ext.grid.PropertyColumnModel, Ext.grid.ColumnModel, {
// private - strings used for locale support
nameText : 'Name',
valueText : 'Value',
dateFormat : 'm/j/Y',
// private
renderDate : function(dateVal) {
return dateVal.dateFormat(this.dateFormat);
},
// private
renderBool : function(bVal) {
return bVal ? 'true' : 'false';
},
// private
isCellEditable : function(colIndex, rowIndex) {
return colIndex == 1;
},
// private
getRenderer : function(col) {
return col == 1
? this.renderCellDelegate
: this.renderPropDelegate;
},
// private
renderProp : function(v) {
return this.getPropertyName(v);
},
// private
renderCell : function(val) {
var rv = val;
if (val instanceof Date) {
rv = this.renderDate(val);
} else if (typeof val == 'boolean') {
rv = this.renderBool(val);
}
return Ext.util.Format.htmlEncode(rv);
},
// private
getPropertyName : function(name) {
var pn = this.grid.propertyNames;
return pn && pn[name] ? pn[name] : name;
},
// private
getCellEditor : function(colIndex, rowIndex) {
var p = this.store.getProperty(rowIndex);
var n = p.data['name'], val = p.data['value'];
if (this.grid.customEditors[n]) {
return this.grid.customEditors[n];
}
if (val instanceof Date) {
return this.editors['date'];
} else if (typeof val == 'number') {
return this.editors['number'];
} else if (typeof val == 'boolean') {
return this.editors['boolean'];
} else {
return this.editors['string'];
}
}
});
/**
* @class Ext.grid.PropertyGrid
* @extends Ext.grid.EditorGridPanel A specialized grid implementation intended
* to mimic the traditional property grid as typically seen in
* development IDEs. Each row in the grid represents a property of some
* object, and the data is stored as a set of name/value pairs in
* {@link Ext.grid.PropertyRecord}s. Example usage:
*
*
* var grid = new Ext.grid.PropertyGrid({
* title : 'Properties Grid',
* autoHeight : true,
* width : 300,
* renderTo : 'grid-ct',
* source : {
* "(name)" : "My Object",
* "Created" : new Date(Date.parse('10/15/2006')),
* "Available" : false,
* "Version" : .01,
* "Description" : "A test object"
* }
* });
*
* @constructor
* @param {Object}
* config The grid config object
*/
Ext.grid.PropertyGrid = Ext.extend(Ext.grid.EditorGridPanel, {
/**
* @cfg {Object} source A data object to use as the data source of
* the grid (see {@link #setSource} for details).
*/
/**
* @cfg {Object} customEditors An object containing name/value pairs
* of custom editor type definitions that allow the grid to
* support additional types of editable fields. By default, the
* grid supports strongly-typed editing of strings, dates,
* numbers and booleans using built-in form editors, but any
* custom type can be supported and associated with a custom
* input control by specifying a custom editor. The name of the
* editor type should correspond with the name of the property
* that will use the editor. Example usage:
*
*
* var grid = new Ext.grid.PropertyGrid({
* ...
* customEditors: {
* 'Start Time': new Ext.grid.GridEditor(new Ext.form.TimeField({selectOnFocus:true}))
* },
* source: {
* 'Start Time': '10:00 AM'
* }
* });
*
*
*/
// private config overrides
enableColLock : false,
enableColumnMove : false,
stripeRows : false,
trackMouseOver : false,
clicksToEdit : 1,
enableHdMenu : false,
viewConfig : {
forceFit : true
},
// private
initComponent : function() {
this.customEditors = this.customEditors || {};
this.lastEditRow = null;
var store = new Ext.grid.PropertyStore(this);
this.propStore = store;
var cm = new Ext.grid.PropertyColumnModel(this, store);
store.store.sort('name', 'ASC');
this.addEvents(
/**
* @event beforepropertychange Fires before a property
* value changes. Handlers can return false to
* cancel the property change (this will
* internally call {@link Ext.data.Record#reject}
* on the property's record).
* @param {Object}
* source The source data object for the grid
* (corresponds to the same object passed in
* as the {@link #source} config property).
* @param {String}
* recordId The record's id in the data store
* @param {Mixed}
* value The current edited property value
* @param {Mixed}
* oldValue The original property value prior
* to editing
*/
'beforepropertychange',
/**
* @event propertychange Fires after a property value
* has changed.
* @param {Object}
* source The source data object for the grid
* (corresponds to the same object passed in
* as the {@link #source} config property).
* @param {String}
* recordId The record's id in the data store
* @param {Mixed}
* value The current edited property value
* @param {Mixed}
* oldValue The original property value prior
* to editing
*/
'propertychange');
this.cm = cm;
this.ds = store.store;
Ext.grid.PropertyGrid.superclass.initComponent.call(this);
this.selModel.on('beforecellselect', function(sm, rowIndex,
colIndex) {
if (colIndex === 0) {
this.startEditing.defer(200, this,
[rowIndex, 1]);
return false;
}
}, this);
},
// private
onRender : function() {
Ext.grid.PropertyGrid.superclass.onRender
.apply(this, arguments);
this.getGridEl().addClass('x-props-grid');
},
// private
afterRender : function() {
Ext.grid.PropertyGrid.superclass.afterRender.apply(this,
arguments);
if (this.source) {
this.setSource(this.source);
}
},
/**
* Sets the source data object containing the property data. The
* data object can contain one or more name/value pairs representing
* all of the properties of an object to display in the grid, and
* this data will automatically be loaded into the grid's
* {@link #store}. If the grid already contains data, this method
* will replace any existing data. See also the {@link #source}
* config value. Example usage:
*
*
* grid.setSource({
* "(name)" : "My Object",
* "Created" : new Date(Date.parse('10/15/2006')),
* "Available" : false,
* "Version" : .01,
* "Description" : "A test object"
* });
*
*
* @param {Object}
* source The data object
*/
setSource : function(source) {
this.propStore.setSource(source);
},
/**
* Gets the source data object containing the property data. See
* {@link #setSource} for details regarding the format of the data
* object.
*
* @return {Object} The data object
*/
getSource : function() {
return this.propStore.getSource();
}
});