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
25 Ext.define('Ext.grid.property.Grid', {
27 extend: 'Ext.grid.Panel',
29 alias: 'widget.propertygrid',
31 alternateClassName: 'Ext.grid.PropertyGrid',
34 'Ext.grid.plugin.CellEditing',
35 'Ext.grid.property.Store',
36 'Ext.grid.property.HeaderContainer',
38 'Ext.grid.CellEditor',
39 'Ext.form.field.Date',
40 'Ext.form.field.Text',
41 'Ext.form.field.Number'
45 * @cfg {Object} propertyNames An object containing custom property name/display name pairs.
46 * If specified, the display name will be shown in the name column instead of the property name.
50 * @cfg {Object} source A data object to use as the data source of the grid (see {@link #setSource} for details).
54 * @cfg {Object} customEditors An object containing name/value pairs of custom editor type definitions that allow
55 * the grid to support additional types of editable fields. By default, the grid supports strongly-typed editing
56 * of strings, dates, numbers and booleans using built-in form editors, but any custom type can be supported and
57 * associated with a custom input control by specifying a custom editor. The name of the editor
58 * type should correspond with the name of the property that will use the editor. Example usage:
60 var grid = new Ext.grid.property.Grid({
62 // Custom editors for certain property names
64 evtStart: Ext.create('Ext.form.TimeField' {selectOnFocus:true})
67 // Displayed name for property names in the source
69 evtStart: 'Start Time'
72 // Data object containing properties to edit
81 * @cfg {Object} source A data object to use as the data source of the grid (see {@link #setSource} for details).
85 * @cfg {Object} customRenderers An object containing name/value pairs of custom renderer type definitions that allow
86 * the grid to support custom rendering of fields. By default, the grid supports strongly-typed rendering
87 * of strings, dates, numbers and booleans using built-in form editors, but any custom type can be supported and
88 * associated with the type of the value. The name of the renderer type should correspond with the name of the property
89 * that it will render. Example usage:
91 var grid = Ext.create('Ext.grid.property.Grid', {
93 Available: function(v){
95 return '<span style="color: green;">Yes</span>';
97 return '<span style="color: red;">No</span>';
109 * @cfg {String} valueField
110 * Optional. The name of the field from the property store to use as the value field name. Defaults to <code>'value'</code>
111 * This may be useful if you do not configure the property Grid from an object, but use your own store configuration.
116 * @cfg {String} nameField
117 * Optional. The name of the field from the property store to use as the property field name. Defaults to <code>'name'</code>
118 * This may be useful if you do not configure the property Grid from an object, but use your own store configuration.
122 // private config overrides
123 enableColumnMove: false,
126 trackMouseOver: false,
131 initComponent : function(){
134 me.addCls(Ext.baseCSSPrefix + 'property-grid');
135 me.plugins = me.plugins || [];
137 // Enable cell editing. Inject a custom startEdit which always edits column 1 regardless of which column was clicked.
138 me.plugins.push(Ext.create('Ext.grid.plugin.CellEditing', {
139 clicksToEdit: me.clicksToEdit,
141 // Inject a startEdit which always edits the value column
142 startEdit: function(record, column) {
143 // Maintainer: Do not change this 'this' to 'me'! It is the CellEditing object's own scope.
144 Ext.grid.plugin.CellEditing.prototype.startEdit.call(this, record, me.headerCt.child('#' + me.valueField));
149 selType: 'cellmodel',
150 onCellSelect: function(position) {
151 if (position.column != 1) {
153 Ext.selection.CellModel.prototype.onCellSelect.call(this, position);
157 me.customRenderers = me.customRenderers || {};
158 me.customEditors = me.customEditors || {};
160 // Create a property.Store from the source object unless configured with a store
162 me.propStore = me.store = Ext.create('Ext.grid.property.Store', me, me.source);
165 me.store.sort('name', 'ASC');
166 me.columns = Ext.create('Ext.grid.property.HeaderContainer', me, me.store);
170 * @event beforepropertychange
171 * Fires before a property value changes. Handlers can return false to cancel the property change
172 * (this will internally call {@link Ext.data.Record#reject} on the property's record).
173 * @param {Object} source The source data object for the grid (corresponds to the same object passed in
174 * as the {@link #source} config property).
175 * @param {String} recordId The record's id in the data store
176 * @param {Mixed} value The current edited property value
177 * @param {Mixed} oldValue The original property value prior to editing
179 'beforepropertychange',
181 * @event propertychange
182 * Fires after a property value has changed.
183 * @param {Object} source The source data object for the grid (corresponds to the same object passed in
184 * as the {@link #source} config property).
185 * @param {String} recordId The record's id in the data store
186 * @param {Mixed} value The current edited property value
187 * @param {Mixed} oldValue The original property value prior to editing
193 // Inject a custom implementation of walkCells which only goes up or down
194 me.getView().walkCells = this.walkCells;
196 // Set up our default editor set for the 4 atomic data types
198 'date' : Ext.create('Ext.grid.CellEditor', { field: Ext.create('Ext.form.field.Date', {selectOnFocus: true})}),
199 'string' : Ext.create('Ext.grid.CellEditor', { field: Ext.create('Ext.form.field.Text', {selectOnFocus: true})}),
200 'number' : Ext.create('Ext.grid.CellEditor', { field: Ext.create('Ext.form.field.Number', {selectOnFocus: true})}),
201 'boolean' : Ext.create('Ext.grid.CellEditor', { field: Ext.create('Ext.form.field.ComboBox', {
203 store: [[ true, me.headerCt.trueText ], [false, me.headerCt.falseText ]]
207 // Track changes to the data so we can fire our events.
208 this.store.on('update', me.onUpdate, me);
212 onUpdate : function(store, record, operation) {
216 if (operation == Ext.data.Model.EDIT) {
217 v = record.get(me.valueField);
218 oldValue = record.modified.value;
219 if (me.fireEvent('beforepropertychange', me.source, record.getId(), v, oldValue) !== false) {
221 me.source[record.getId()] = v;
224 me.fireEvent('propertychange', me.source, record.getId(), v, oldValue);
231 // Custom implementation of walkCells which only goes up and down.
232 walkCells: function(pos, direction, e, preventWrap, verifierFn, scope) {
233 if (direction == 'left') {
235 } else if (direction == 'right') {
238 pos = Ext.view.Table.prototype.walkCells.call(this, pos, direction, e, preventWrap, verifierFn, scope);
246 // returns the correct editor type for the property type, or a custom one keyed by the property name
247 getCellEditor : function(record, column) {
249 propName = record.get(me.nameField),
250 val = record.get(me.valueField),
251 editor = me.customEditors[propName];
253 // A custom editor was found. If not already wrapped with a CellEditor, wrap it, and stash it back
254 // If it's not even a Field, just a config object, instantiate it before wrapping it.
256 if (!(editor instanceof Ext.grid.CellEditor)) {
257 if (!(editor instanceof Ext.form.field.Base)) {
258 editor = Ext.ComponentManager.create(editor, 'textfield');
260 editor = me.customEditors[propName] = Ext.create('Ext.grid.CellEditor', { field: editor });
262 } else if (Ext.isDate(val)) {
263 editor = me.editors.date;
264 } else if (Ext.isNumber(val)) {
265 editor = me.editors.number;
266 } else if (Ext.isBoolean(val)) {
267 editor = me.editors['boolean'];
269 editor = me.editors.string;
272 // Give the editor a unique ID because the CellEditing plugin caches them
273 editor.editorId = propName;
277 beforeDestroy: function() {
280 me.destroyEditors(me.editors);
281 me.destroyEditors(me.customEditors);
285 destroyEditors: function (editors) {
286 for (var ed in editors) {
287 if (editors.hasOwnProperty(ed)) {
288 Ext.destroy(editors[ed]);
294 * Sets the source data object containing the property data. The data object can contain one or more name/value
295 * pairs representing all of the properties of an object to display in the grid, and this data will automatically
296 * be loaded into the grid's {@link #store}. The values should be supplied in the proper data type if needed,
297 * otherwise string type will be assumed. If the grid already contains data, this method will replace any
298 * existing data. See also the {@link #source} config value. Example usage:
301 "(name)": "My Object",
302 "Created": Ext.Date.parse('10/15/2006', 'm/d/Y'), // date type
303 "Available": false, // boolean type
304 "Version": .01, // decimal type
305 "Description": "A test object"
308 * @param {Object} source The data object
310 setSource: function(source) {
311 this.source = source;
312 this.propStore.setSource(source);
316 * Gets the source data object containing the property data. See {@link #setSource} for details regarding the
317 * format of the data object.
318 * @return {Object} The data object
320 getSource: function() {
321 return this.propStore.getSource();
325 * Sets the value of a property.
326 * @param {String} prop The name of the property to set
327 * @param {Mixed} value The value to test
328 * @param {Boolean} create (Optional) True to create the property if it doesn't already exist. Defaults to <tt>false</tt>.
330 setProperty: function(prop, value, create) {
331 this.propStore.setValue(prop, value, create);
335 * Removes a property from the grid.
336 * @param {String} prop The name of the property to remove
338 removeProperty: function(prop) {
339 this.propStore.remove(prop);