/**
* The rowbody feature enhances the grid's markup to have an additional
* tr -> td -> div which spans the entire width of the original row.
*
* This is useful to to associate additional information with a particular
* record in an Ext.grid.Grid.
*
* Rowbodies are initially hidden unless you override {@link #getAdditionalData}.
*
* The events fired by RowBody are relayed to the owning
* {@link Ext.view.Table grid view} (and subsequently the owning grid).
*
* # Example
*
* @example
* Ext.define('Animal', {
* extend: 'Ext.data.Model',
* fields: ['name', 'latin', 'desc', 'lifespan']
* });
*
* Ext.create('Ext.grid.Panel', {
* width: 400,
* height: 300,
* renderTo: Ext.getBody(),
* store: {
* model: 'Animal',
* data: [{
* name: 'Tiger',
* latin: 'Panthera tigris',
* desc: 'The largest cat species, weighing up to 306 kg (670 lb).',
* lifespan: '20 - 26 years (in captivity)'
* }, {
* name: 'Roman snail',
* latin: 'Helix pomatia',
* desc: 'A species of large, edible, air-breathing land snail.',
* lifespan: '20 - 35 years'
* }, {
* name: 'Yellow-winged darter',
* latin: 'Sympetrum flaveolum',
* desc: 'A dragonfly found in Europe and mid and Northern China.',
* lifespan: '4 - 6 weeks'
* }, {
* name: 'Superb Fairy-wren',
* latin: 'Malurus cyaneus',
* desc: 'Common and familiar across south-eastern Australia.',
* lifespan: '5 - 6 years'
* }]
* },
* columns: [{
* dataIndex: 'name',
* text: 'Common name',
* width: 125
* }, {
* dataIndex: 'latin',
* text: 'Scientific name',
* flex: 1
* }],
* features: [{
* ftype: 'rowbody',
* getAdditionalData: function (data, idx, record, orig) {
* // Usually you would style the my-body-class in a CSS file
* return {
* rowBody: '<div style="padding: 1em">' + record.get("desc") + '</div>',
* rowBodyCls: "my-body-class"
* };
* }
* }],
* listeners: {
* rowbodyclick: function(view, rowEl, e, eOpts) {
* var itemEl = Ext.get(rowEl).up(view.itemSelector),
* rec = view.getRecord(itemEl);
*
* Ext.Msg.alert(rec.get('name') + ' life span', rec.get('lifespan'));
* }
* }
* });
*
* # Cell Editing and Cell Selection Model
*
* Note that if {@link Ext.grid.plugin.CellEditing cell editing} or the {@link Ext.selection.CellModel cell selection model} are going
* to be used, then the {@link Ext.grid.feature.RowBody RowBody} feature, or {@link Ext.grid.plugin.RowExpander RowExpander} plugin MUST
* be used for intra-cell navigation to be correct.
*
* **Note:** The {@link Ext.grid.plugin.RowExpander rowexpander} plugin and the rowbody
* feature are exclusive and cannot both be set on the same grid / tree.
*/
Ext.define('Ext.grid.feature.RowBody', {
extend: 'Ext.grid.feature.Feature',
alias: 'feature.rowbody',
rowBodyCls: Ext.baseCSSPrefix + 'grid-row-body',
innerSelector: '.' + Ext.baseCSSPrefix + 'grid-rowbody',
rowBodyHiddenCls: Ext.baseCSSPrefix + 'grid-row-body-hidden',
rowBodyTdSelector: 'td.' + Ext.baseCSSPrefix + 'grid-cell-rowbody',
eventPrefix: 'rowbody',
eventSelector: 'tr.' + Ext.baseCSSPrefix + 'grid-rowbody-tr',
/**
* @cfg {Boolean} [bodyBefore=false]
* Configure as `true` to put the row expander body *before* the data row.
*/
bodyBefore: false,
outerTpl: {
fn: function(out, values, parent) {
var me = this.rowBody,
view = values.view,
columns = view.getVisibleColumnManager().getColumns(),
rowValues = view.rowValues,
rowExpanderCol = me.rowExpander && me.rowExpander.expanderColumn;
rowValues.rowBodyColspan = columns.length;
rowValues.rowBodyCls = me.rowBodyCls;
rowValues.rowIdCls = me.rowIdCls;
if (rowExpanderCol && rowExpanderCol.getView() === view) {
view.grid.removeCls(Ext.baseCSSPrefix + 'grid-hide-row-expander-spacer');
rowValues.addSpacerCell = true;
rowValues.rowBodyColspan -= 1;
rowValues.spacerCellCls = Ext.baseCSSPrefix + 'grid-cell ' + Ext.baseCSSPrefix + 'grid-row-expander-spacer ' + Ext.baseCSSPrefix + 'grid-cell-special';
} else {
view.grid.addCls(Ext.baseCSSPrefix + 'grid-hide-row-expander-spacer');
rowValues.addSpacerCell = false;
}
this.nextTpl.applyOut(values, out, parent);
rowValues.rowBodyCls = rowValues.rowBodyColspan = rowValues.rowBody = null;
},
priority: 100
},
extraRowTpl: [
'{%',
'if(this.rowBody.bodyBefore) {',
// MUST output column sizing elements because the first row in this table
// contains one colspanning TD, and that overrides subsequent column width settings.
'values.view.renderColumnSizer(values, out);',
'} else {',
'this.nextTpl.applyOut(values, out, parent);',
'}',
'values.view.rowBodyFeature.setupRowData(values.record, values.recordIndex, values);',
'%}',
'<tr class="' + Ext.baseCSSPrefix + 'grid-rowbody-tr {rowBodyCls} {rowIdCls}" {ariaRowAttr}>',
'<tpl if="addSpacerCell">',
'<td class="{spacerCellCls}"></td>',
'</tpl>',
'<td class="' + Ext.baseCSSPrefix + 'grid-td ' + Ext.baseCSSPrefix + 'grid-cell-rowbody" colspan="{rowBodyColspan}" {ariaCellAttr}>',
'<div class="' + Ext.baseCSSPrefix + 'grid-rowbody {rowBodyDivCls}" {ariaCellInnerAttr}>{rowBody}</div>',
'</td>',
'</tr>',
'{%',
'if(this.rowBody.bodyBefore) {',
'this.nextTpl.applyOut(values, out, parent);',
'}',
'%}', {
priority: 100,
beginRowSync: function (rowSync) {
rowSync.add('rowBody', this.owner.eventSelector);
},
syncContent: function(destRow, sourceRow, columnsToUpdate) {
var owner = this.owner,
destRowBody = Ext.fly(destRow).down(owner.eventSelector, true),
sourceRowBody;
// Sync the heights of row body elements in each row if they need it.
if (destRowBody && (sourceRowBody = Ext.fly(sourceRow).down(owner.eventSelector, true))) {
Ext.fly(destRowBody).syncContent(sourceRowBody);
}
}
}
],
init: function(grid) {
var me = this,
view = me.view = grid.getView();
// <debug>
if (!me.rowExpander && grid.findPlugin('rowexpander')) {
Ext.raise('The RowBody feature shouldn\'t be manually added when the grid has a RowExpander.');
}
// </debug>
// The extra data means variableRowHeight
grid.variableRowHeight = view.variableRowHeight = true;
view.rowBodyFeature = me;
view.headerCt.on({
columnschanged: me.onColumnsChanged,
scope: me
});
view.addTpl(me.outerTpl).rowBody = me;
view.addRowTpl(Ext.XTemplate.getTpl(this, 'extraRowTpl')).rowBody = me;
me.callParent(arguments);
},
getSelectedRow: function(view, rowIndex) {
var selectedRow = view.getNode(rowIndex);
if (selectedRow) {
return Ext.fly(selectedRow).down(this.eventSelector);
}
return null;
},
// When columns added/removed, keep row body colspan in sync with number of columns.
onColumnsChanged: function(headerCt) {
var items = this.view.el.query(this.rowBodyTdSelector),
colspan = headerCt.getVisibleGridColumns().length,
len = items.length,
i;
for (i = 0; i < len; ++i) {
items[i].setAttribute('colSpan', colspan);
}
},
/**
* @method getAdditionalData
* @protected
* @template
* Provides additional data to the prepareData call within the grid view.
* The rowbody feature adds 3 additional variables into the grid view's template.
* These are `rowBody`, `rowBodyCls`, and `rowBodyColspan`.
*
* - **rowBody:** *{String}* The HTML to display in the row body element. Defaults
* to *undefined*.
* - **rowBodyCls:** *{String}* An optional CSS class (or multiple classes
* separated by spaces) to apply to the row body element. Defaults to
* {@link #rowBodyCls}.
* - **rowBodyColspan:** *{Number}* The number of columns that the row body element
* should span. Defaults to the number of visible columns.
*
* @param {Object} data The data for this particular record.
* @param {Number} idx The row index for this record.
* @param {Ext.data.Model} record The record instance
* @param {Object} orig The original result from the prepareData call to massage.
* @return {Object} An object containing additional variables for use in the grid
* view's template
*/
/*
* @private
*/
setupRowData: function(record, rowIndex, rowValues) {
if (this.getAdditionalData) {
Ext.apply(rowValues, this.getAdditionalData(record.data, rowIndex, record, rowValues));
}
}
/**
* @event beforerowbodymousedown
* @preventable
* @member Ext.view.Table
* Fires before the mousedown event on a row body element is processed. Return false
* to cancel the default action.
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @param {Ext.view.View} view The rowbody's owning View
* @param {HTMLElement} rowBodyEl The row body's element
* @param {Ext.event.Event} e The raw event object
*/
/**
* @event beforerowbodymouseup
* @preventable
* @member Ext.view.Table
* Fires before the mouseup event on a row body element is processed. Return false
* to cancel the default action.
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @inheritdoc #beforerowbodymousedown
*/
/**
* @event beforerowbodyclick
* @preventable
* @member Ext.view.Table
* Fires before the click event on a row body element is processed. Return false to
* cancel the default action.
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @inheritdoc #beforerowbodymousedown
*/
/**
* @event beforerowbodydblclick
* @preventable
* @member Ext.view.Table
* Fires before the dblclick event on a row body element is processed. Return false
* to cancel the default action.
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @inheritdoc #beforerowbodymousedown
*/
/**
* @event beforerowbodycontextmenu
* @preventable
* @member Ext.view.Table
* Fires before the contextmenu event on a row body element is processed. Return
* false to cancel the default action.
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @inheritdoc #beforerowbodymousedown
*/
/**
* @event beforerowbodylongpress
* @preventable
* @member Ext.view.Table
* Fires before the longpress event on a row body element is processed. Return
* false to cancel the default action.
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @inheritdoc #beforerowbodymousedown
*/
/**
* @event beforerowbodykeydown
* @preventable
* @member Ext.view.Table
* Fires before the keydown event on a row body element is processed. Return false
* to cancel the default action.
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @inheritdoc #beforerowbodymousedown
*/
/**
* @event beforerowbodykeyup
* @preventable
* @member Ext.view.Table
* Fires before the keyup event on a row body element is processed. Return false to
* cancel the default action.
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @inheritdoc #beforerowbodymousedown
*/
/**
* @event beforerowbodykeypress
* @preventable
* @member Ext.view.Table
* Fires before the keypress event on a row body element is processed. Return false
* to cancel the default action.
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @inheritdoc #beforerowbodymousedown
*/
/**
* @event rowbodymousedown
* @member Ext.view.Table
* Fires when there is a mouse down on a row body element
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @inheritdoc #beforerowbodymousedown
*/
/**
* @event rowbodymouseup
* @member Ext.view.Table
* Fires when there is a mouse up on a row body element
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @inheritdoc #beforerowbodymousedown
*/
/**
* @event rowbodyclick
* @member Ext.view.Table
* Fires when a row body element is clicked
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @inheritdoc #beforerowbodymousedown
*/
/**
* @event rowbodydblclick
* @member Ext.view.Table
* Fires when a row body element is double clicked
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @inheritdoc #beforerowbodymousedown
*/
/**
* @event rowbodycontextmenu
* @member Ext.view.Table
* Fires when a row body element is right clicked
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @inheritdoc #beforerowbodymousedown
*/
/**
* @event rowbodylongpress
* @member Ext.view.Table
* Fires on a row body element longpress event
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @inheritdoc #beforerowbodymousedown
*/
/**
* @event rowbodykeydown
* @member Ext.view.Table
* Fires when a key is pressed down while a row body element is currently selected
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @inheritdoc #beforerowbodymousedown
*/
/**
* @event rowbodykeyup
* @member Ext.view.Table
* Fires when a key is released while a row body element is currently selected
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @inheritdoc #beforerowbodymousedown
*/
/**
* @event rowbodykeypress
* @member Ext.view.Table
* Fires when a key is pressed while a row body element is currently selected.
*
* **Note:** This event is fired only when the Ext.grid.feature.RowBody feature is
* used.
*
* @inheritdoc #beforerowbodymousedown
*/
});