2 * @class Ext.grid.property.Grid
3 * @extends Ext.grid.Panel
4 * A specialized grid implementation intended to mimic the traditional property grid as typically seen in
5 * development IDEs. Each row in the grid represents a property of some object, and the data is stored
6 * as a set of name/value pairs in {@link Ext.grid.property.Property Properties}. Example usage:
8 var grid = new Ext.grid.property.Grid({
9 title: 'Properties Grid',
13 "(name)": "My Object",
14 "Created": Ext.Date.parse('10/15/2006', 'm/d/Y'),
17 "Description": "A test object"
22 * @param {Object} config The grid config object
24 Ext.define('Ext.grid.property.Grid', {
26 extend: 'Ext.grid.Panel',
28 alternateClassName: 'Ext.grid.PropertyGrid',
31 'Ext.grid.plugin.CellEditing',
32 'Ext.grid.property.Store',
33 'Ext.grid.property.HeaderContainer',
35 'Ext.grid.CellEditor',
36 'Ext.form.field.Date',
37 'Ext.form.field.Text',
38 'Ext.form.field.Number'
42 * @cfg {Object} propertyNames An object containing custom property name/display name pairs.
43 * If specified, the display name will be shown in the name column instead of the property name.
47 * @cfg {Object} source A data object to use as the data source of the grid (see {@link #setSource} for details).
51 * @cfg {Object} customEditors An object containing name/value pairs of custom editor type definitions that allow
52 * the grid to support additional types of editable fields. By default, the grid supports strongly-typed editing
53 * of strings, dates, numbers and booleans using built-in form editors, but any custom type can be supported and
54 * associated with a custom input control by specifying a custom editor. The name of the editor
55 * type should correspond with the name of the property that will use the editor. Example usage:
57 var grid = new Ext.grid.property.Grid({
59 // Custom editors for certain property names
61 evtStart: Ext.create('Ext.form.TimeField' {selectOnFocus:true})
64 // Displayed name for property names in the source
66 evtStart: 'Start Time'
69 // Data object containing properties to edit
78 * @cfg {Object} source A data object to use as the data source of the grid (see {@link #setSource} for details).
82 * @cfg {Object} customRenderers An object containing name/value pairs of custom renderer type definitions that allow
83 * the grid to support custom rendering of fields. By default, the grid supports strongly-typed rendering
84 * of strings, dates, numbers and booleans using built-in form editors, but any custom type can be supported and
85 * associated with the type of the value. The name of the renderer type should correspond with the name of the property
86 * that it will render. Example usage:
88 var grid = Ext.create('Ext.grid.property.Grid', {
90 Available: function(v){
92 return '<span style="color: green;">Yes</span>';
94 return '<span style="color: red;">No</span>';
106 * @cfg {String} valueField
107 * Optional. The name of the field from the property store to use as the value field name. Defaults to <code>'value'</code>
108 * This may be useful if you do not configure the property Grid from an object, but use your own store configuration.
113 * @cfg {String} nameField
114 * Optional. The name of the field from the property store to use as the property field name. Defaults to <code>'name'</code>
115 * This may be useful if you do not configure the property Grid from an object, but use your own store configuration.
119 // private config overrides
120 enableColumnMove: false,
123 trackMouseOver: false,
128 initComponent : function(){
131 me.addCls(Ext.baseCSSPrefix + 'property-grid');
132 me.plugins = me.plugins || [];
134 // Enable cell editing. Inject a custom startEdit which always edits column 1 regardless of which column was clicked.
135 me.plugins.push(Ext.create('Ext.grid.plugin.CellEditing', {
136 clicksToEdit: me.clicksToEdit,
138 // Inject a startEdit which always edits the value column
139 startEdit: function(record, column) {
140 // Maintainer: Do not change this 'this' to 'me'! It is the CellEditing object's own scope.
141 Ext.grid.plugin.CellEditing.prototype.startEdit.call(this, record, me.headerCt.child('#' + me.valueField));
146 selType: 'cellmodel',
147 onCellSelect: function(position) {
148 if (position.column != 1) {
150 Ext.selection.CellModel.prototype.onCellSelect.call(this, position);
154 me.customRenderers = me.customRenderers || {};
155 me.customEditors = me.customEditors || {};
157 // Create a property.Store from the source object unless configured with a store
159 me.propStore = me.store = Ext.create('Ext.grid.property.Store', me, me.source);
162 me.store.sort('name', 'ASC');
163 me.columns = Ext.create('Ext.grid.property.HeaderContainer', me, me.store);
167 * @event beforepropertychange
168 * Fires before a property value changes. Handlers can return false to cancel the property change
169 * (this will internally call {@link Ext.data.Record#reject} on the property's record).
170 * @param {Object} source The source data object for the grid (corresponds to the same object passed in
171 * as the {@link #source} config property).
172 * @param {String} recordId The record's id in the data store
173 * @param {Mixed} value The current edited property value
174 * @param {Mixed} oldValue The original property value prior to editing
176 'beforepropertychange',
178 * @event propertychange
179 * Fires after a property value has changed.
180 * @param {Object} source The source data object for the grid (corresponds to the same object passed in
181 * as the {@link #source} config property).
182 * @param {String} recordId The record's id in the data store
183 * @param {Mixed} value The current edited property value
184 * @param {Mixed} oldValue The original property value prior to editing
190 // Inject a custom implementation of walkCells which only goes up or down
191 me.getView().walkCells = this.walkCells;
193 // Set up our default editor set for the 4 atomic data types
195 'date' : Ext.create('Ext.grid.CellEditor', { field: Ext.create('Ext.form.field.Date', {selectOnFocus: true})}),
196 'string' : Ext.create('Ext.grid.CellEditor', { field: Ext.create('Ext.form.field.Text', {selectOnFocus: true})}),
197 'number' : Ext.create('Ext.grid.CellEditor', { field: Ext.create('Ext.form.field.Number', {selectOnFocus: true})}),
198 'boolean' : Ext.create('Ext.grid.CellEditor', { field: Ext.create('Ext.form.field.ComboBox', {
200 store: [[ true, me.headerCt.trueText ], [false, me.headerCt.falseText ]]
204 // Track changes to the data so we can fire our events.
205 this.store.on('update', me.onUpdate, me);
209 onUpdate : function(store, record, operation) {
213 if (operation == Ext.data.Model.EDIT) {
214 v = record.get(me.valueField);
215 oldValue = record.modified.value;
216 if (me.fireEvent('beforepropertychange', me.source, record.id, v, oldValue) !== false) {
218 me.source[record.id] = v;
221 me.fireEvent('propertychange', me.source, record.id, v, oldValue);
228 // Custom implementation of walkCells which only goes up and down.
229 walkCells: function(pos, direction, e, preventWrap, verifierFn, scope) {
230 if (direction == 'left') {
232 } else if (direction == 'right') {
235 var pos = Ext.view.Table.prototype.walkCells.call(this, pos, direction, e, preventWrap, verifierFn, scope);
243 // returns the correct editor type for the property type, or a custom one keyed by the property name
244 getCellEditor : function(record, column) {
246 propName = record.get(me.nameField),
247 val = record.get(me.valueField),
248 editor = me.customEditors[propName];
250 // A custom editor was found. If not already wrapped with a CellEditor, wrap it, and stash it back
251 // If it's not even a Field, just a config object, instantiate it before wrapping it.
253 if (!(editor instanceof Ext.grid.CellEditor)) {
254 if (!(editor instanceof Ext.form.field.Base)) {
255 editor = Ext.ComponentManager.create(editor, 'textfield');
257 editor = me.customEditors[propName] = Ext.create('Ext.grid.CellEditor', { field: editor });
259 } else if (Ext.isDate(val)) {
260 editor = me.editors.date;
261 } else if (Ext.isNumber(val)) {
262 editor = me.editors.number;
263 } else if (Ext.isBoolean(val)) {
264 editor = me.editors['boolean'];
266 editor = me.editors.string;
269 // Give the editor a unique ID because the CellEditing plugin caches them
270 editor.editorId = propName;
274 beforeDestroy: function() {
277 me.destroyEditors(me.editors);
278 me.destroyEditors(me.customEditors);
282 destroyEditors: function (editors) {
283 for (var ed in editors) {
284 Ext.destroy(editors[ed]);
289 * Sets the source data object containing the property data. The data object can contain one or more name/value
290 * pairs representing all of the properties of an object to display in the grid, and this data will automatically
291 * be loaded into the grid's {@link #store}. The values should be supplied in the proper data type if needed,
292 * otherwise string type will be assumed. If the grid already contains data, this method will replace any
293 * existing data. See also the {@link #source} config value. Example usage:
296 "(name)": "My Object",
297 "Created": Ext.Date.parse('10/15/2006', 'm/d/Y'), // date type
298 "Available": false, // boolean type
299 "Version": .01, // decimal type
300 "Description": "A test object"
303 * @param {Object} source The data object
305 setSource: function(source) {
306 this.source = source;
307 this.propStore.setSource(source);
311 * Gets the source data object containing the property data. See {@link #setSource} for details regarding the
312 * format of the data object.
313 * @return {Object} The data object
315 getSource: function() {
316 return this.propStore.getSource();
320 * Sets the value of a property.
321 * @param {String} prop The name of the property to set
322 * @param {Mixed} value The value to test
323 * @param {Boolean} create (Optional) True to create the property if it doesn't already exist. Defaults to <tt>false</tt>.
325 setProperty: function(prop, value, create) {
326 this.propStore.setValue(prop, value, create);
330 * Removes a property from the grid.
331 * @param {String} prop The name of the property to remove
333 removeProperty: function(prop) {
334 this.propStore.remove(prop);