<!DOCTYPE html>
|
<html>
|
<head>
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<title>The source code</title>
|
<link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
|
<script type="text/javascript" src="../resources/prettify/prettify.js"></script>
|
<style type="text/css">
|
.highlight { display: block; background-color: #ddd; }
|
</style>
|
<script type="text/javascript">
|
function highlight() {
|
document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
|
}
|
</script>
|
</head>
|
<body onload="prettyPrint(); highlight();">
|
<pre class="prettyprint lang-js"><span id='Ext-grid-property-Grid'>/**
|
</span> * 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.property.Property Properties}. By default, the editors
|
* shown are inferred from the data in the cell. More control over this can be specified by using the
|
* {@link #sourceConfig} option. Example usage:
|
*
|
* @example
|
* Ext.create('Ext.grid.property.Grid', {
|
* title: 'Properties Grid',
|
* width: 300,
|
* renderTo: Ext.getBody(),
|
* source: {
|
* "(name)": "My Object",
|
* "Created": Ext.Date.parse('10/15/2006', 'm/d/Y'),
|
* "Available": false,
|
* "Version": 0.01,
|
* "Description": "A test object"
|
* }
|
* });
|
*/
|
Ext.define('Ext.grid.property.Grid', {
|
|
extend: 'Ext.grid.Panel',
|
|
alias: 'widget.propertygrid',
|
|
alternateClassName: 'Ext.grid.PropertyGrid',
|
|
uses: [
|
'Ext.grid.plugin.CellEditing',
|
'Ext.grid.property.Store',
|
'Ext.grid.property.HeaderContainer',
|
'Ext.XTemplate',
|
'Ext.grid.CellEditor',
|
'Ext.form.field.Date',
|
'Ext.form.field.Text',
|
'Ext.form.field.Number',
|
'Ext.form.field.ComboBox'
|
],
|
|
<span id='Ext-grid-property-Grid-cfg-sourceConfig'> /**
|
</span> * @cfg {Object} sourceConfig
|
* This option allows various configurations to be set for each field in the property grid.
|
* None of these configurations are required
|
*
|
* ####displayName
|
* A custom name to appear as label for this field. If specified, the display name will be shown
|
* in the name column instead of the property name. Example usage:
|
*
|
* new Ext.grid.property.Grid({
|
* source: {
|
* clientIsAvailable: true
|
* },
|
* sourceConfig: {
|
* clientIsAvailable: {
|
* // Custom name different to the field
|
* displayName: 'Available'
|
* }
|
* }
|
* });
|
*
|
* ####renderer
|
* A function used to transform the underlying value before it is displayed in the grid.
|
* By default, the grid supports strongly-typed rendering of strings, dates, numbers and booleans using built-in form editors,
|
* but any custom type can be supported and associated with the type of the value. Example usage:
|
*
|
* new Ext.grid.property.Grid({
|
* source: {
|
* clientIsAvailable: true
|
* },
|
* sourceConfig: {
|
* clientIsAvailable: {
|
* // Custom renderer to change the color based on the value
|
* renderer: function(v){
|
* var color = v ? 'green' : 'red';
|
* return '<span style="color: ' + color + ';">' + v + '</span>';
|
* }
|
* }
|
* }
|
* });
|
*
|
* ####type
|
* Used to explicitly specify the editor type for a particular value. By default, the type is
|
* automatically inferred from the value. See {@link #inferTypes}. Accepted values are:
|
*
|
* - 'date'
|
* - 'boolean'
|
* - 'number'
|
* - 'string'
|
*
|
* For more advanced control an editor configuration can be passed (see the next section).
|
* Example usage:
|
*
|
* new Ext.grid.property.Grid({
|
* source: {
|
* attending: null
|
* },
|
* sourceConfig: {
|
* attending: {
|
* // Force the type to be a numberfield, a null value would otherwise default to a textfield
|
* type: 'number'
|
* }
|
* }
|
* });
|
*
|
* ####editor
|
* Allows 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. Example usage
|
*
|
* new Ext.grid.property.Grid({
|
* // Data object containing properties to edit
|
* source: {
|
* evtStart: '10:00 AM'
|
* },
|
*
|
* sourceConfig: {
|
* evtStart: {
|
* editor: Ext.create('Ext.form.field.Time', {selectOnFocus: true}),
|
* displayName: 'Start Time'
|
* }
|
* }
|
* });
|
*/
|
|
<span id='Ext-grid-property-Grid-cfg-propertyNames'> /**
|
</span> * @cfg {Object} propertyNames
|
* An object containing custom property name/display name pairs.
|
* If specified, the display name will be shown in the name column instead of the property name.
|
* @deprecated See {@link #sourceConfig} displayName
|
*/
|
|
<span id='Ext-grid-property-Grid-cfg-source'> /**
|
</span> * @cfg {Object} source
|
* A data object to use as the data source of the grid (see {@link #setSource} for details).
|
*/
|
|
<span id='Ext-grid-property-Grid-cfg-customEditors'> /**
|
</span> * @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.property.Grid({
|
*
|
* // Custom editors for certain property names
|
* customEditors: {
|
* evtStart: Ext.create('Ext.form.TimeField', {selectOnFocus: true})
|
* },
|
*
|
* // Displayed name for property names in the source
|
* propertyNames: {
|
* evtStart: 'Start Time'
|
* },
|
*
|
* // Data object containing properties to edit
|
* source: {
|
* evtStart: '10:00 AM'
|
* }
|
* });
|
* @deprecated See {@link #sourceConfig} editor
|
*/
|
|
<span id='Ext-grid-property-Grid-cfg-customRenderers'> /**
|
</span> * @cfg {Object} customRenderers
|
* An object containing name/value pairs of custom renderer type definitions that allow
|
* the grid to support custom rendering of fields. By default, the grid supports strongly-typed rendering
|
* of strings, dates, numbers and booleans using built-in form editors, but any custom type can be supported and
|
* associated with the type of the value. The name of the renderer type should correspond with the name of the property
|
* that it will render. Example usage:
|
*
|
* var grid = Ext.create('Ext.grid.property.Grid', {
|
* customRenderers: {
|
* Available: function(v){
|
* if (v) {
|
* return '<span style="color: green;">Yes</span>';
|
* } else {
|
* return '<span style="color: red;">No</span>';
|
* }
|
* }
|
* },
|
* source: {
|
* Available: true
|
* }
|
* });
|
* @deprecated See {@link #sourceConfig} renderer
|
*/
|
|
<span id='Ext-grid-property-Grid-cfg-valueField'> /**
|
</span> * @cfg {String} valueField
|
* The name of the field from the property store to use as the value field name.
|
* This may be useful if you do not configure the property Grid from an object, but use your own store configuration.
|
*/
|
valueField: 'value',
|
|
<span id='Ext-grid-property-Grid-cfg-nameField'> /**
|
</span> * @cfg {String} nameField
|
* The name of the field from the property store to use as the property field name.
|
* This may be useful if you do not configure the property Grid from an object, but use your own store configuration.
|
*/
|
nameField: 'name',
|
|
<span id='Ext-grid-property-Grid-cfg-inferTypes'> /**
|
</span> * @cfg {Boolean} inferTypes
|
* True to automatically infer the {@link #sourceConfig type} based on the initial value passed
|
* for each field. This ensures the editor remains the correct type even if the value is blanked
|
* and becomes empty.
|
*/
|
inferTypes: true,
|
|
<span id='Ext-grid-property-Grid-cfg-nameColumnWidth'> /**
|
</span> * @cfg {Number/String} [nameColumnWidth=115]
|
* Specify the width for the name column. The value column will take any remaining space.
|
*/
|
|
<span id='Ext-grid-property-Grid-cfg-enableColumnMove'> // private config overrides
|
</span> enableColumnMove: false,
|
<span id='Ext-grid-property-Grid-cfg-columnLines'> columnLines: true,
|
</span><span id='Ext-grid-property-Grid-property-stripeRows'> stripeRows: false,
|
</span><span id='Ext-grid-property-Grid-property-trackMouseOver'> trackMouseOver: false,
|
</span><span id='Ext-grid-property-Grid-property-clicksToEdit'> clicksToEdit: 1,
|
</span><span id='Ext-grid-property-Grid-property-enableHdMenu'> enableHdMenu: false,
|
</span>
|
<span id='Ext-grid-property-Grid-property-gridCls'> gridCls: Ext.baseCSSPrefix + 'property-grid',
|
</span>
|
<span id='Ext-grid-property-Grid-method-initComponent'> // private
|
</span> initComponent : function(){
|
var me = this;
|
|
me.source = me.source || {};
|
me.addCls(me.gridCls);
|
me.plugins = me.plugins || [];
|
|
// Enable cell editing. Inject a custom startEdit which always edits column 1 regardless of which column was clicked.
|
me.plugins.push(new Ext.grid.plugin.CellEditing({
|
clicksToEdit: me.clicksToEdit,
|
|
// Inject a startEdit which always edits the value column
|
startEdit: function(record, column) {
|
// Maintainer: Do not change this 'this' to 'me'! It is the CellEditing object's own scope.
|
return this.self.prototype.startEdit.call(this, record, me.headerCt.child('#' + me.valueField));
|
}
|
}));
|
|
me.selModel = {
|
selType: 'cellmodel',
|
onCellSelect: function(position) {
|
if (position.column != 1) {
|
position.column = 1;
|
}
|
return this.self.prototype.onCellSelect.call(this, position);
|
}
|
};
|
|
me.sourceConfig = Ext.apply({}, me.sourceConfig);
|
|
// Create a property.Store from the source object unless configured with a store
|
if (!me.store) {
|
me.propStore = me.store = new Ext.grid.property.Store(me, me.source);
|
}
|
me.configure(me.sourceConfig);
|
|
if (me.sortableColumns) {
|
me.store.sort('name', 'ASC');
|
}
|
me.columns = new Ext.grid.property.HeaderContainer(me, me.store);
|
|
me.addEvents(
|
<span id='Ext-grid-property-Grid-event-beforepropertychange'> /**
|
</span> * @event beforepropertychange
|
* Fires before a property value changes. Handlers can return false to cancel the property change
|
* (this will internally call {@link Ext.data.Model#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 {Object} value The current edited property value
|
* @param {Object} oldValue The original property value prior to editing
|
*/
|
'beforepropertychange',
|
<span id='Ext-grid-property-Grid-event-propertychange'> /**
|
</span> * @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 {Object} value The current edited property value
|
* @param {Object} oldValue The original property value prior to editing
|
*/
|
'propertychange'
|
);
|
me.callParent();
|
|
// Inject a custom implementation of walkCells which only goes up or down
|
me.getView().walkCells = this.walkCells;
|
|
// Set up our default editor set for the 4 atomic data types
|
me.editors = {
|
'date' : new Ext.grid.CellEditor({ field: new Ext.form.field.Date({selectOnFocus: true})}),
|
'string' : new Ext.grid.CellEditor({ field: new Ext.form.field.Text({selectOnFocus: true})}),
|
'number' : new Ext.grid.CellEditor({ field: new Ext.form.field.Number({selectOnFocus: true})}),
|
'boolean' : new Ext.grid.CellEditor({ field: new Ext.form.field.ComboBox({
|
editable: false,
|
store: [[ true, me.headerCt.trueText ], [false, me.headerCt.falseText ]]
|
})})
|
};
|
|
// Track changes to the data so we can fire our events.
|
me.store.on('update', me.onUpdate, me);
|
},
|
|
<span id='Ext-grid-property-Grid-method-configure'> configure: function(config){
|
</span> var me = this,
|
store = me.store,
|
i = 0,
|
len = me.store.getCount(),
|
nameField = me.nameField,
|
valueField = me.valueField,
|
name, value, rec, type;
|
|
me.configureLegacy(config);
|
|
if (me.inferTypes) {
|
for (; i < len; ++i) {
|
rec = store.getAt(i);
|
name = rec.get(nameField);
|
if (!me.getConfig(name, 'type')) {
|
value = rec.get(valueField);
|
if (Ext.isDate(value)) {
|
type = 'date';
|
} else if (Ext.isNumber(value)) {
|
type = 'number';
|
} else if (Ext.isBoolean(value)) {
|
type = 'boolean';
|
} else {
|
type = 'string';
|
}
|
me.setConfig(name, 'type', type);
|
}
|
}
|
}
|
},
|
|
<span id='Ext-grid-property-Grid-method-getConfig'> getConfig: function(fieldName, key, defaultValue) {
|
</span> var config = this.sourceConfig[fieldName],
|
out;
|
|
if (config) {
|
out = config[key];
|
}
|
return out || defaultValue;
|
},
|
|
<span id='Ext-grid-property-Grid-method-setConfig'> setConfig: function(fieldName, key, value) {
|
</span> var sourceCfg = this.sourceConfig,
|
o = sourceCfg[fieldName];
|
|
if (!o) {
|
o = sourceCfg[fieldName] = {
|
__copied: true
|
};
|
} else if (!o.__copied) {
|
o = Ext.apply({
|
__copied: true
|
}, o);
|
sourceCfg[fieldName] = o;
|
}
|
o[key] = value;
|
return value;
|
},
|
|
<span id='Ext-grid-property-Grid-method-configureLegacy'> // to be deprecated in 4.2
|
</span> configureLegacy: function(config){
|
var me = this,
|
o, key, value;
|
|
me.copyLegacyObject(config, me.customRenderers, 'renderer');
|
me.copyLegacyObject(config, me.customEditors, 'editor');
|
me.copyLegacyObject(config, me.propertyNames, 'displayName');
|
|
//<debug>
|
// exclude types since it's new
|
if (me.customRenderers || me.customEditors || me.propertyNames) {
|
if (Ext.global.console && Ext.global.console.warn) {
|
Ext.global.console.warn(this.$className, 'customRenderers, customEditors & propertyNames have been consolidated into a new config, see "sourceConfig". These configurations will be deprecated.');
|
}
|
}
|
//</debug>
|
},
|
|
<span id='Ext-grid-property-Grid-method-copyLegacyObject'> copyLegacyObject: function(config, o, keyName){
|
</span> var key, value;
|
|
for (key in o) {
|
if (o.hasOwnProperty(key)) {
|
if (!config[key]) {
|
config[key] = {};
|
}
|
config[key][keyName] = o[key];
|
}
|
}
|
},
|
|
<span id='Ext-grid-property-Grid-method-onUpdate'> // @private
|
</span> onUpdate : function(store, record, operation) {
|
var me = this,
|
v, oldValue;
|
|
if (me.rendered && operation == Ext.data.Model.EDIT) {
|
v = record.get(me.valueField);
|
oldValue = record.modified.value;
|
if (me.fireEvent('beforepropertychange', me.source, record.getId(), v, oldValue) !== false) {
|
if (me.source) {
|
me.source[record.getId()] = v;
|
}
|
record.commit();
|
me.fireEvent('propertychange', me.source, record.getId(), v, oldValue);
|
} else {
|
record.reject();
|
}
|
}
|
},
|
|
<span id='Ext-grid-property-Grid-method-walkCells'> // Custom implementation of walkCells which only goes up and down.
|
</span> walkCells: function(pos, direction, e, preventWrap, verifierFn, scope) {
|
if (direction == 'left') {
|
direction = 'up';
|
} else if (direction == 'right') {
|
direction = 'down';
|
}
|
pos = Ext.view.Table.prototype.walkCells.call(this, pos, direction, e, preventWrap, verifierFn, scope);
|
if (pos && !pos.column) {
|
pos.column = 1;
|
}
|
return pos;
|
},
|
|
<span id='Ext-grid-property-Grid-method-getCellEditor'> // @private
|
</span> // Returns the correct editor type for the property type, or a custom one keyed by the property name
|
getCellEditor : function(record, column) {
|
var me = this,
|
propName = record.get(me.nameField),
|
val = record.get(me.valueField),
|
editor = me.getConfig(propName, 'editor'),
|
type = me.getConfig(propName, 'type'),
|
editors = me.editors;
|
|
// A custom editor was found. If not already wrapped with a CellEditor, wrap it, and stash it back
|
// If it's not even a Field, just a config object, instantiate it before wrapping it.
|
if (editor) {
|
if (!(editor instanceof Ext.grid.CellEditor)) {
|
if (!(editor instanceof Ext.form.field.Base)) {
|
editor = Ext.ComponentManager.create(editor, 'textfield');
|
}
|
editor = me.setConfig(propName, 'editor', new Ext.grid.CellEditor({ field: editor }));
|
}
|
} else if (type) {
|
switch (type) {
|
case 'date':
|
editor = editors.date;
|
break;
|
case 'number':
|
editor = editors.number;
|
break;
|
case 'boolean':
|
editor = me.editors['boolean'];
|
break;
|
default:
|
editor = editors.string;
|
}
|
} else if (Ext.isDate(val)) {
|
editor = editors.date;
|
} else if (Ext.isNumber(val)) {
|
editor = editors.number;
|
} else if (Ext.isBoolean(val)) {
|
editor = editors['boolean'];
|
} else {
|
editor = editors.string;
|
}
|
|
// Give the editor a unique ID because the CellEditing plugin caches them
|
editor.editorId = propName;
|
return editor;
|
},
|
|
<span id='Ext-grid-property-Grid-method-beforeDestroy'> beforeDestroy: function() {
|
</span> var me = this;
|
me.callParent();
|
me.destroyEditors(me.editors);
|
me.destroyEditors(me.customEditors);
|
delete me.source;
|
},
|
|
<span id='Ext-grid-property-Grid-method-destroyEditors'> destroyEditors: function (editors) {
|
</span> for (var ed in editors) {
|
if (editors.hasOwnProperty(ed)) {
|
Ext.destroy(editors[ed]);
|
}
|
}
|
},
|
|
<span id='Ext-grid-property-Grid-method-setSource'> /**
|
</span> * 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}. The values should be supplied in the proper data type if needed,
|
* otherwise string type will be assumed. 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": Ext.Date.parse('10/15/2006', 'm/d/Y'), // date type
|
* "Available": false, // boolean type
|
* "Version": .01, // decimal type
|
* "Description": "A test object"
|
* });
|
*
|
* @param {Object} source The data object.
|
* @param {Object} [sourceConfig] A new {@link #sourceConfig object}. If this argument is not passed
|
* the current configuration will be re-used. To reset the config, pass `null` or an empty object literal.
|
*/
|
setSource: function(source, sourceConfig) {
|
var me = this;
|
|
me.source = source;
|
if (sourceConfig !== undefined) {
|
me.sourceConfig = Ext.apply({}, sourceConfig);
|
me.configure(me.sourceConfig);
|
}
|
me.propStore.setSource(source);
|
},
|
|
<span id='Ext-grid-property-Grid-method-getSource'> /**
|
</span> * 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();
|
},
|
|
<span id='Ext-grid-property-Grid-method-setProperty'> /**
|
</span> * Sets the value of a property.
|
* @param {String} prop The name of the property to set.
|
* @param {Object} value The value to test.
|
* @param {Boolean} [create=false] `true` to create the property if it doesn't already exist.
|
*/
|
setProperty: function(prop, value, create) {
|
this.propStore.setValue(prop, value, create);
|
},
|
|
<span id='Ext-grid-property-Grid-method-removeProperty'> /**
|
</span> * Removes a property from the grid.
|
* @param {String} prop The name of the property to remove.
|
*/
|
removeProperty: function(prop) {
|
this.propStore.remove(prop);
|
}
|
|
<span id='Ext-grid-property-Grid-cfg-store'> /**
|
</span> * @cfg {Object} store
|
* @private
|
*/
|
<span id='Ext-grid-property-Grid-cfg-columns'> /**
|
</span> * @cfg {Object} columns
|
* @private
|
*/
|
});
|
</pre>
|
</body>
|
</html>
|