/** * This is the default cell class for {@link Ext.grid.Grid grid} cells. Use this class if * you use the {@link Ext.grid.column.Column#renderer} or {@link Ext.grid.column.Column#tpl} * configs for a column. * * {@link Ext.grid.Row Rows} create cells based on the {@link Ext.grid.column.Column#cell} * config. Application code would rarely create cells directly. */Ext.define('Ext.grid.cell.Cell', { extend: 'Ext.grid.cell.Text', xtype: 'gridcell', config: { /** * @cfg {String/String[]/Ext.XTemplate} tpl * An {@link Ext.XTemplate XTemplate}, or an XTemplate *definition string* to use * to process a {@link Ext.data.Model records} data to produce a cell's rendered * value. * * @example * Ext.create('Ext.data.Store', { * storeId:'employeeStore', * fields:['firstname', 'lastname', 'seniority', 'department'], * groupField: 'department', * data:[ * { firstname: "Michael", lastname: "Scott", seniority: 7, department: "Management" }, * { firstname: "Dwight", lastname: "Schrute", seniority: 2, department: "Sales" }, * { firstname: "Jim", lastname: "Halpert", seniority: 3, department: "Sales" }, * { firstname: "Kevin", lastname: "Malone", seniority: 4, department: "Accounting" }, * { firstname: "Angela", lastname: "Martin", seniority: 5, department: "Accounting" } * ] * }); * * Ext.create('Ext.grid.Panel', { * title: 'Column Template Demo', * store: Ext.data.StoreManager.lookup('employeeStore'), * columns: [{ * text: 'Full Name', * tpl: '{firstname} {lastname}' * }, { * text: 'Department (Yrs)', * tpl: '{department} ({seniority})' * }], * height: 200, * width: 300, * renderTo: Ext.getBody() * }); * * This config is only processed if the {@link #cell} type is the default of * {@link Ext.grid.cell.Cell gridcell}. * * **Note** See {@link Ext.grid.Grid} documentation for other, better * alternatives to rendering cell content. */ tpl: null, /** * @cfg {Function/String} renderer * A renderer is a method which can be used to transform data (value, appearance, * etc.) before it is rendered. * * For example: * * { * text: 'Some column', * dataIndex: 'fieldName', * * renderer: function (value, record) { * if (value === 1) { * return '1 person'; * } * return value + ' people'; * } * } * * If a string is supplied, it should be the name of a renderer method from the * appropriate {@link Ext.app.ViewController}. * * This config is only processed if the * {@link Ext.grid.column.Column#cfg-cell cell} type is the default of * {@link Ext.grid.cell.Cell gridcell}. * * **Note** See {@link Ext.grid.Grid} documentation for other, better * alternatives to rendering cell content. * * @param {Object} renderer.value The data value for the current cell * * renderer: function (value) { * return value + (value === 'F' ? ' (failed)' : ''); * } * * @param {Ext.data.Model} renderer.record The {@link Ext.data.Model record} for * the current row * * renderer: function (value, record) { * return value + (record.get('isNew') ? ' (★)' : ''); * } * * @param {Number} renderer.dataIndex The * {@link Ext.grid.column.Column#cfg-dataIndex dataIndex} of the current column * * // ViewController * // ... * evalDate: function (value, record, dataIndex) { * var dateRe = new RegExp(/.*date$/, 'i'), * D = Ext.Date, * elapsed; * * if (dateRe.test(dataIndex)) { * let now = new Date(), * days = D.diff(value, now, Ext.Date.DAY), * hours = new Date(now - value).elapsed.getHours(), * ret = []; * * if (days) { * ret.push(days + 'd'); * } * if (hours) { * ret.push(hours + 'hr'); * } * * return ret.join(' '); * } else { * return value; * } * } * // ... * * // renderer config using the shared ViewController 'evalDate' method * renderer: 'evalDate' * * @param {Ext.grid.cell.Base} renderer.cell The current * {@link Ext.grid.cell.Cell cell} * * renderer: function (value, record, dataIndex, cell) { * if (value === 'F') { * cell.setCls('failing-grade'); * } * return value; * } * * @param {Ext.grid.column.Column} renderer.column The current * {@link Ext.grid.column.Column column} * * renderer: function (value, record, dataIndex, cell, column) { * var header = column.getClosestVisibleHeader(column), * count = record.store.getCount(); * * header.setText(header.getText() + ' (' + count + ')'); * * return value; * } * * @return {String} The HTML string to be rendered. * *Note*: to render HTML into the cell, you will have to configure the column's * {@link #cell} with `{@link Ext.grid.column.Column#cfg-encodeHtml encodeHtml}: * false` */ renderer: null, /** * @cfg {String} formatter * This config accepts a format specification as would be used in a * `Ext.Template` formatted token. For example `'round(2)'` to round numbers to 2 * decimal places or `'date("Y-m-d")'` to format a Date. * * In previous releases the `renderer` config had limited abilities to use one * of the `Ext.util.Format` methods but `formatter` now replaces that usage and * can also handle formatting parameters. * * When the value begins with `"this."` (for example, `"this.foo(2)"`), the * implied scope on which "foo" is found is the `scope` config for the column. * * If the `scope` is not given, or implied using a prefix of `"this"`, then * either the {@link #method-getController ViewController} or the closest * ancestor component configured as {@link #defaultListenerScope} is assumed to * be the object with the method. * @since 6.2.0 */ formatter: null, /** * @cfg {Object} scope * The scope to use when calling the {@link #renderer} or {@link #formatter} * function. */ scope: null }, friendly: null, updateColumn: function (column, oldColumn) { var me = this, friendly = true, tpl, renderer, formatter; me.callParent([ column, oldColumn ]); /* The `tpl`, `renderer` and `formatter` configs are on the Cell level so that a ViewModel can be used for cells to change these configs dynamically. If `formatter` is changed dynamically then performance will decrease since expressions need to be parsed for each cell. */ if (column) { tpl = column.getTpl(); renderer = column.getRenderer(); formatter = column.getFormatter(); if (renderer !== null) { me.setRenderer(renderer); friendly = (typeof renderer === 'function') && renderer.length === 1; } if (tpl !== null) { me.setTpl(tpl); friendly = false; } if (formatter !== null) { me.setFormatter(formatter); } me.friendly = friendly; } }, applyTpl: function (tpl) { return Ext.XTemplate.get(tpl); }, applyFormatter: function (format) { var me = this, fmt = format, parser; if (typeof fmt === 'string') { parser = Ext.app.bind.Parser.fly(fmt); fmt = parser.compileFormat(); parser.release(); return function (v) { return fmt(v, me.getScope() || me.resolveListenerScope()); }; } //<debug> else if (typeof fmt !== 'function') { Ext.raise('Invalid formatter'); } //</debug> return fmt; }, updateTpl: function () { if (!this.isConfiguring) { this.refresh(); } }, updateRenderer: function () { if (!this.isConfiguring) { this.refresh(); } }, updateFormatter: function () { if (!this.isConfiguring) { this.refresh(); } }, formatValue: function (v) { var me = this, context = me.refreshContext, dataIndex = context.dataIndex, column = context.column, record = context.record, zeroValue = me.getZeroValue(), raw = v, // raw value takes as default the cell value summary = context.summary, args, data, format, renderer, scope, tpl; if (!context.summary && v === 0 && zeroValue !== null) { raw = zeroValue; } else if (!(tpl = me.getTpl(context))) { format = me.getFormatter(); if (summary) { renderer = column.getSummaryRenderer(); if (renderer) { format = null; // ignore the non-summary formatter scope = context.scope; if (typeof renderer === 'string') { raw = Ext.callback(renderer, scope, [ v, context ], 0, column); me.friendly = false; } else { raw = renderer.call(scope || me, v, context); if (renderer.length > 1) { me.friendly = false; } } } format = column.getSummaryFormatter() || format; } else { renderer = me.getRenderer(); if (renderer) { args = [v, record, dataIndex, me, column]; scope = me.getScope() || context.scope; if (typeof renderer === 'function') { raw = renderer.apply(scope || column, args); } else { raw = Ext.callback(renderer, scope, args, 0, me); } } } if (format) { raw = format(raw); } } else { // We have either: // cell: { tpl: '...' } // or: // summaryCell: { tpl: '...' } if (!(data = context.data)) { context.data = data = context.summary ? context.record.getData() : context.grid.gatherData(context.record); } raw = tpl.apply(data); } if (raw != null) { raw = String(raw); } else { raw = ''; } return raw; }, privates: { bound: function (fields) { var me = this, bound = !!fields[me.dataIndex], column, depends, i; if (!bound) { column = me.getColumn(); depends = column && column.getDepends(); if (depends) { for (i = depends.length; !bound && i-- > 0; ) { bound = !!fields[depends[i]]; } } else if (!me.friendly) { bound = true; } } return bound; } }});