]> git.proxmox.com Git - extjs.git/blame - extjs/classic/classic/src/grid/column/Widget.js
add extjs 6.0.1 sources
[extjs.git] / extjs / classic / classic / src / grid / column / Widget.js
CommitLineData
6527f429
DM
1/**\r
2 * A widget column is configured with a {@link #widget} config object which specifies an\r
3 * {@link Ext.Component#cfg-xtype xtype} to indicate which type of Widget or Component belongs\r
4 * in the cells of this column.\r
5 *\r
6 * When a widget cell is rendered, a {@link Ext.Widget Widget} or {@link Ext.Component Component} of the specified type\r
7 * is rendered into that cell. Its {@link Ext.Component#defaultBindProperty defaultBindProperty} is set using this\r
8 * column's {@link #dataIndex} field from the associated record.\r
9 *\r
10 * In the example below we are monitoring the throughput of electricity substations. The capacity being\r
11 * used as a proportion of the maximum rated capacity is displayed as a progress bar. As new data arrives and the\r
12 * instantaneous usage value is updated, the `capacityUsed` field updates itself, and\r
13 * that is used as the {@link #dataIndex} for the `WidgetColumn` which contains the\r
14 * progress bar. The progress Bar's\r
15 * {@link Ext.ProgressBarWidget#defaultBindProperty defaultBindProperty} (which is\r
16 * "value") is set to the calculated `capacityUsed`.\r
17 *\r
18 * @example\r
19 * var grid = new Ext.grid.Panel({\r
20 * title: 'Substation power monitor',\r
21 * width: 600,\r
22 * columns: [{\r
23 * text: 'Id',\r
24 * dataIndex: 'id',\r
25 * width: 120\r
26 * }, {\r
27 * text: 'Rating',\r
28 * dataIndex: 'maxCapacity',\r
29 * width: 80\r
30 * }, {\r
31 * text: 'Avg.',\r
32 * dataIndex: 'avg',\r
33 * width: 85,\r
34 * formatter: 'number("0.00")'\r
35 * }, {\r
36 * text: 'Max',\r
37 * dataIndex: 'max',\r
38 * width: 80\r
39 * }, {\r
40 * text: 'Instant',\r
41 * dataIndex: 'instant',\r
42 * width: 80\r
43 * }, {\r
44 * text: '%Capacity',\r
45 * width: 150,\r
46 *\r
47 * // This is our Widget column\r
48 * xtype: 'widgetcolumn',\r
49 * dataIndex: 'capacityUsed',\r
50 *\r
51 * // This is the widget definition for each cell.\r
52 * // Its "value" setting is taken from the column's dataIndex\r
53 * widget: {\r
54 * xtype: 'progressbarwidget',\r
55 * textTpl: [\r
56 * '{percent:number("0")}% capacity'\r
57 * ]\r
58 * }\r
59 * }],\r
60 * renderTo: document.body,\r
61 * disableSelection: true,\r
62 * store: {\r
63 * fields: [{\r
64 * name: 'id',\r
65 * type: 'string'\r
66 * }, {\r
67 * name: 'maxCapacity',\r
68 * type: 'int'\r
69 * }, {\r
70 * name: 'avg',\r
71 * type: 'int',\r
72 * calculate: function(data) {\r
73 * // Make this depend upon the instant field being set which sets the sampleCount and total.\r
74 * // Use subscript format to access the other pseudo fields which are set by the instant field's converter\r
75 * return data.instant && data['total'] / data['sampleCount'];\r
76 * }\r
77 * }, {\r
78 * name: 'max',\r
79 * type: 'int',\r
80 * calculate: function(data) {\r
81 * // This will be seen to depend on the "instant" field.\r
82 * // Use subscript format to access this field's current value to avoid circular dependency error.\r
83 * return (data['max'] || 0) < data.instant ? data.instant : data['max'];\r
84 * }\r
85 * }, {\r
86 * name: 'instant',\r
87 * type: 'int',\r
88 *\r
89 * // Upon every update of instantaneous power throughput,\r
90 * // update the sample count and total so that the max field can calculate itself\r
91 * convert: function(value, rec) {\r
92 * rec.data.sampleCount = (rec.data.sampleCount || 0) + 1;\r
93 * rec.data.total = (rec.data.total || 0) + value;\r
94 * return value;\r
95 * },\r
96 * depends: []\r
97 * }, {\r
98 * name: 'capacityUsed',\r
99 * calculate: function(data) {\r
100 * return data.instant / data.maxCapacity;\r
101 * }\r
102 * }],\r
103 * data: [{\r
104 * id: 'Substation A',\r
105 * maxCapacity: 1000,\r
106 * avg: 770,\r
107 * max: 950,\r
108 * instant: 685\r
109 * }, {\r
110 * id: 'Substation B',\r
111 * maxCapacity: 1000,\r
112 * avg: 819,\r
113 * max: 992,\r
114 * instant: 749\r
115 * }, {\r
116 * id: 'Substation C',\r
117 * maxCapacity: 1000,\r
118 * avg: 588,\r
119 * max: 936,\r
120 * instant: 833\r
121 * }, {\r
122 * id: 'Substation D',\r
123 * maxCapacity: 1000,\r
124 * avg: 639,\r
125 * max: 917,\r
126 * instant: 825\r
127 * }]\r
128 * }\r
129 * });\r
130 *\r
131 * // Fake data updating...\r
132 * // Change one record per second to a random power value\r
133 * Ext.interval(function() {\r
134 * var recIdx = Ext.Number.randomInt(0, 3),\r
135 * newPowerReading = Ext.Number.randomInt(500, 1000);\r
136 *\r
137 * grid.store.getAt(recIdx).set('instant', newPowerReading);\r
138 * }, 1000);\r
139 *\r
140 * @since 5.0.0\r
141 */\r
142Ext.define('Ext.grid.column.Widget', {\r
143 extend: 'Ext.grid.column.Column',\r
144 alias: 'widget.widgetcolumn',\r
145\r
146 config: {\r
147 /**\r
148 * @cfg defaultWidgetUI\r
149 * A map of xtype to {@link Ext.Component#ui} names to use when using Components in this column.\r
150 *\r
151 * Currently {@link Ext.Button Button} and all subclasses of {@link Ext.form.field.Text TextField} default\r
152 * to using `ui: "default"` when in a WidgetColumn except for in the "classic" theme, when they use ui "grid-cell".\r
153 */\r
154 defaultWidgetUI: {}\r
155 },\r
156\r
157 ignoreExport: true,\r
158\r
159 /**\r
160 * @cfg\r
161 * @inheritdoc\r
162 */\r
163 sortable: false,\r
164\r
165 /**\r
166 * @cfg {Object} renderer\r
167 * @hide\r
168 */\r
169\r
170 /**\r
171 * @cfg {Object} scope\r
172 * @hide\r
173 */\r
174\r
175 /**\r
176 * @cfg {Object} widget\r
177 * A config object containing an {@link Ext.Component#cfg-xtype xtype}.\r
178 *\r
179 * This is used to create the widgets or components which are rendered into the cells of this column.\r
180 *\r
181 * This column's {@link #dataIndex} is used to update the widget/component's {@link Ext.Component#defaultBindProperty defaultBindProperty}.\r
182 *\r
183 * The widget will be decorated with 2 methods:\r
184 * `getWidgetRecord` - Returns the {@link Ext.data.Model record} the widget is associated with.\r
185 * `getWidgetColumn` - Returns the {@link Ext.grid.column.Widget column} the widget \r
186 * was associated with.\r
187 */\r
188 \r
189 /**\r
190 * @cfg {Function/String} onWidgetAttach\r
191 * A function that will be called when a widget is attached to a record. This may be useful for\r
192 * doing any post-processing.\r
193 * \r
194 * Ext.create({\r
195 * xtype: 'grid',\r
196 * title: 'Student progress report',\r
197 * width: 250,\r
198 * renderTo: Ext.getBody(),\r
199 * disableSelection: true,\r
200 * store: {\r
201 * fields: ['name', 'isHonorStudent'],\r
202 * data: [{\r
203 * name: 'Finn',\r
204 * isHonorStudent: true\r
205 * }, {\r
206 * name: 'Jake',\r
207 * isHonorStudent: false\r
208 * }]\r
209 * },\r
210 * columns: [{\r
211 * text: 'Name',\r
212 * dataIndex: 'name',\r
213 * flex: 1\r
214 * }, {\r
215 * xtype: 'widgetcolumn',\r
216 * text: 'Honor Roll',\r
217 * dataIndex: 'isHonorStudent',\r
218 * width: 150,\r
219 * widget: {\r
220 * xtype: 'button',\r
221 * handler: function() {\r
222 * // print certificate handler\r
223 * }\r
224 * },\r
225 * // called when the widget is initially instantiated\r
226 * // on the widget column\r
227 * onWidgetAttach: function(col, widget, rec) {\r
228 * widget.setText('Print Certificate');\r
229 * widget.setDisabled(!rec.get('isHonorStudent'));\r
230 * }\r
231 * }]\r
232 * });\r
233 * \r
234 * @param {Ext.grid.column.Column} column The column.\r
235 * @param {Ext.Component/Ext.Widget} widget The {@link #widget} rendered to each cell.\r
236 * @param {Ext.data.Model} record The record used with the current widget (cell).\r
237 * @declarativeHandler\r
238 */\r
239 onWidgetAttach: null,\r
240\r
241 preventUpdate: true,\r
242\r
243 /**\r
244 * @cfg {Boolean} [stopSelection=true]\r
245 * Prevent grid selection upon click on the widget.\r
246 */\r
247 stopSelection: true,\r
248\r
249 initComponent: function() {\r
250 var me = this,\r
251 widget;\r
252\r
253 me.callParent(arguments);\r
254\r
255 widget = me.widget;\r
256 //<debug>\r
257 if (!widget || widget.isComponent) {\r
258 Ext.raise('column.Widget requires a widget configuration.');\r
259 }\r
260 //</debug>\r
261 me.widget = widget = Ext.apply({}, widget);\r
262\r
263 // Apply the default UI for the xtype which is going to feature in this column.\r
264 if (!widget.ui) {\r
265 widget.ui = me.getDefaultWidgetUI()[widget.xtype] || 'default';\r
266 }\r
267 me.isFixedSize = Ext.isNumber(widget.width);\r
268 },\r
269\r
270 processEvent : function(type, view, cell, recordIndex, cellIndex, e, record, row) {\r
271 var target;\r
272 \r
273 if (this.stopSelection && type === 'click') {\r
274 // Grab the target that matches the cell inner selector. If we have a target, then,\r
275 // that means we either clicked on the inner part or the widget inside us. If \r
276 // target === e.target, then it was on the cell, so it's ok. Otherwise, inside so\r
277 // prevent the selection from happening\r
278 target = e.getTarget(view.innerSelector);\r
279 if (target && target !== e.target) {\r
280 e.stopSelection = true;\r
281 }\r
282 }\r
283 },\r
284\r
285 beforeRender: function() {\r
286 var me = this,\r
287 tdCls = me.tdCls,\r
288 widget;\r
289\r
290 me.listenerScopeFn = function (defaultScope) {\r
291 if (defaultScope === 'this') {\r
292 return this;\r
293 }\r
294 return me.resolveListenerScope(defaultScope);\r
295 };\r
296\r
297 me.liveWidgets = {};\r
298 me.cachedStyles = {};\r
299 me.freeWidgetStack = [widget = me.getFreeWidget()];\r
300\r
301 tdCls = tdCls ? tdCls + ' ' : '';\r
302 me.tdCls = tdCls + widget.getTdCls();\r
303 me.setupViewListeners(me.getView());\r
304 me.callParent();\r
305 },\r
306\r
307 afterRender: function() {\r
308 var view = this.getView();\r
309\r
310 this.callParent();\r
311 // View already ready, means we were added later so go and set up our widgets, but if the grid\r
312 // is reconfiguring, then the column will be rendered & the view will be ready, so wait until\r
313 // the reconfigure forces a refresh\r
314 if (view && view.viewReady && !view.ownerGrid.reconfiguring) {\r
315 this.onViewRefresh(view, view.getViewRange());\r
316 }\r
317 },\r
318\r
319 // Cell must be left blank\r
320 defaultRenderer: Ext.emptyFn, \r
321\r
322 updater: function(cell, value, record) {\r
323 this.updateWidget(record);\r
324 },\r
325\r
326 onResize: function(newWidth) {\r
327 var me = this,\r
328 liveWidgets = me.liveWidgets,\r
329 view = me.getView(),\r
330 id, cell;\r
331\r
332 if (!me.isFixedSize && me.rendered && view && view.viewReady) {\r
333 cell = view.getEl().down(me.getCellInnerSelector());\r
334 if (cell) {\r
335 // Subtract innerCell padding width\r
336 newWidth -= parseInt(me.getCachedStyle(cell, 'padding-left'), 10) + parseInt(me.getCachedStyle(cell, 'padding-right'), 10);\r
337\r
338 for (id in liveWidgets) {\r
339 liveWidgets[id].setWidth(newWidth);\r
340 }\r
341 }\r
342 }\r
343 },\r
344\r
345 onAdded: function() {\r
346 var me = this,\r
347 view;\r
348\r
349 me.callParent(arguments);\r
350\r
351 view = me.getView();\r
352\r
353 // If we are being added to a rendered HeaderContainer\r
354 if (view) {\r
355 me.setupViewListeners(view);\r
356\r
357 if (view && view.viewReady && me.rendered && view.getEl().down(me.getCellSelector())) {\r
358 // If the view is ready, it means we're already rendered.\r
359 // At this point the view may refresh "soon", however we don't have\r
360 // a way of knowing that the view is pending a refresh, so we need\r
361 // to ensure the widgets get hooked up correctly here\r
362 me.onViewRefresh(view, view.getViewRange());\r
363 }\r
364 }\r
365 },\r
366\r
367 onRemoved: function(isDestroying) {\r
368 var me = this,\r
369 liveWidgets = me.liveWidgets,\r
370 viewListeners = me.viewListeners,\r
371 id;\r
372\r
373 if (me.rendered) {\r
374 me.viewListeners = viewListeners && Ext.destroy(viewListeners);\r
375\r
376 // If we are being removed, we have to move all widget elements into the detached body\r
377 if (!isDestroying) {\r
378 for (id in liveWidgets) {\r
379 liveWidgets[id].detachFromBody();\r
380 }\r
381 }\r
382 }\r
383 me.callParent(arguments);\r
384 },\r
385\r
386 onDestroy: function() {\r
387 var me = this,\r
388 oldWidgetMap = me.liveWidgets,\r
389 freeWidgetStack = me.freeWidgetStack,\r
390 id, widget, i, len;\r
391\r
392 if (me.rendered) {\r
393 for (id in oldWidgetMap) {\r
394 widget = oldWidgetMap[id];\r
395 widget.$widgetRecord = widget.$widgetColumn = null;\r
396 delete widget.getWidgetRecord;\r
397 delete widget.getWidgetColumn;\r
398 widget.destroy();\r
399 }\r
400 \r
401 for (i = 0, len = freeWidgetStack.length; i < len; ++i) {\r
402 freeWidgetStack[i].destroy();\r
403 }\r
404 }\r
405 \r
406 me.freeWidgetStack = me.liveWidgets = null;\r
407 \r
408 me.callParent();\r
409 },\r
410\r
411 getWidget: function(record) {\r
412 var liveWidgets = this.liveWidgets,\r
413 widget;\r
414\r
415 if (record && liveWidgets) {\r
416 widget = liveWidgets[record.internalId];\r
417 }\r
418 return widget || null;\r
419 },\r
420\r
421 privates: {\r
422 getCachedStyle: function(el, style) {\r
423 var cachedStyles = this.cachedStyles;\r
424 return cachedStyles[style] || (cachedStyles[style] = Ext.fly(el).getStyle(style));\r
425 },\r
426\r
427 getFreeWidget: function() {\r
428 var me = this,\r
429 result = me.freeWidgetStack ? me.freeWidgetStack.pop() : null;\r
430\r
431 if (!result) {\r
432 result = Ext.widget(me.widget);\r
433\r
434 result.resolveListenerScope = me.listenerScopeFn;\r
435 result.getWidgetRecord = me.widgetRecordDecorator;\r
436 result.getWidgetColumn = me.widgetColumnDecorator;\r
437 result.dataIndex = me.dataIndex;\r
438 result.measurer = me;\r
439 result.ownerCmp = me.getView();\r
440 // The ownerCmp of the widget is the encapsulating view, which means it will be considered\r
441 // as a layout child, but it isn't really, we always need the layout on the\r
442 // component to run if asked.\r
443 result.isLayoutChild = me.returnFalse;\r
444 }\r
445 return result;\r
446 },\r
447\r
448 onBeforeRefresh: function () {\r
449 var liveWidgets = this.liveWidgets,\r
450 id;\r
451\r
452 // Because of a memory leak bug in IE 8, we need to handle the dom node here before\r
453 // it is destroyed.\r
454 // See EXTJS-14874.\r
455 for (id in liveWidgets) {\r
456 liveWidgets[id].detachFromBody();\r
457 }\r
458 },\r
459\r
460 onItemAdd: function(records, index, items) {\r
461 var me = this,\r
462 view = me.getView(),\r
463 hasAttach = !!me.onWidgetAttach,\r
464 dataIndex = me.dataIndex,\r
465 isFixedSize = me.isFixedSize,\r
466 len = records.length, i,\r
467 record,\r
468 row,\r
469 cell,\r
470 widget,\r
471 el,\r
472 focusEl,\r
473 width;\r
474\r
475 // Loop through all records added, ensuring that our corresponding cell in each item\r
476 // has a Widget of the correct type in it, and is updated with the correct value from the record.\r
477 if (me.isVisible(true)) {\r
478 for (i = 0; i < len; i++) {\r
479 record = records[i];\r
480 if (record.isNonData) {\r
481 continue;\r
482 }\r
483\r
484 row = view.getRowFromItem(items[i]);\r
485\r
486 // May be a placeholder with no data row\r
487 if (row) {\r
488 cell = row.cells[me.getVisibleIndex()].firstChild;\r
489 if (!isFixedSize && !width) {\r
490 width = me.lastBox.width - parseInt(me.getCachedStyle(cell, 'padding-left'), 10) - parseInt(me.getCachedStyle(cell, 'padding-right'), 10);\r
491 }\r
492\r
493 widget = me.liveWidgets[record.internalId] = me.getFreeWidget();\r
494 widget.$widgetColumn = me;\r
495 widget.$widgetRecord = record;\r
496\r
497 // Render/move a widget into the new row\r
498 Ext.fly(cell).empty();\r
499\r
500 // Call the appropriate setter with this column's data field\r
501 if (widget.defaultBindProperty && dataIndex) {\r
502 widget.setConfig(widget.defaultBindProperty, record.get(dataIndex));\r
503 }\r
504 \r
505 if (hasAttach) {\r
506 Ext.callback(me.onWidgetAttach, me.scope, [me, widget, record], 0, me);\r
507 }\r
508\r
509 el = widget.el || widget.element;\r
510 if (el) {\r
511 cell.appendChild(el.dom);\r
512 if (!isFixedSize) {\r
513 widget.setWidth(width);\r
514 }\r
515 widget.reattachToBody();\r
516 } else {\r
517 if (!isFixedSize) {\r
518 widget.width = width;\r
519 }\r
520 widget.render(cell);\r
521 }\r
522 \r
523 // If the widget has a focusEl, ensure that its tabbability status is synched with the view's\r
524 // navigable/actionable state.\r
525 focusEl = widget.getFocusEl();\r
526 if (focusEl) {\r
527 if (view.actionableMode) {\r
528 if (!focusEl.isTabbable()) {\r
529 focusEl.restoreTabbableState();\r
530 }\r
531 } else {\r
532 if (focusEl.isTabbable()) {\r
533 focusEl.saveTabbableState();\r
534 }\r
535 }\r
536 }\r
537 }\r
538 }\r
539 }\r
540 },\r
541\r
542 onItemRemove: function(records, index, items) {\r
543 var me = this,\r
544 liveWidgets = me.liveWidgets,\r
545 widget, item, id, len, i, focusEl;\r
546\r
547 if (me.rendered) {\r
548\r
549 // Single item or Array.\r
550 items = Ext.Array.from(items);\r
551 len = items.length;\r
552\r
553 for (i = 0; i < len; i++) {\r
554 item = items[i];\r
555\r
556 // If there was a record ID (collapsed placeholder will no longer be \r
557 // accessible)... return ousted widget to free stack, and move its element \r
558 // to the detached body\r
559 id = item.getAttribute('data-recordId');\r
560 if (id && (widget = liveWidgets[id])) {\r
561 delete liveWidgets[id];\r
562 me.freeWidgetStack.unshift(widget);\r
563 widget.$widgetRecord = widget.$widgetColumn = null;\r
564\r
565 // Focusables in a grid must not be tabbable by default when they get put back in.\r
566 focusEl = widget.getFocusEl();\r
567 if (focusEl) {\r
568 // Widgets are reused so we must reset their tabbable state\r
569 // regardless of their visibility.\r
570 // For example, when removing rows in IE8 we're attaching\r
571 // the nodes to a document-fragment which itself is invisible,\r
572 // so isTabbable() returns false. Next time when we're reusing\r
573 // this widget it will be attached to the document with its\r
574 // tabbable state unreset, which might lead to undesired results.\r
575 if (focusEl.isTabbable(true)) {\r
576 focusEl.saveTabbableState({\r
577 includeHidden: true\r
578 });\r
579 }\r
580\r
581 // Some browsers do not deliver a focus change upon DOM removal.\r
582 // Force the issue here.\r
583 focusEl.blur();\r
584 }\r
585\r
586 widget.detachFromBody();\r
587 }\r
588 }\r
589 }\r
590 },\r
591\r
592 onItemUpdate: function(record, recordIndex, oldItemDom) {\r
593 this.updateWidget(record);\r
594 },\r
595\r
596 onViewRefresh: function(view, records) {\r
597 var me = this,\r
598 rows = view.all,\r
599 hasAttach = !!me.onWidgetAttach,\r
600 oldWidgetMap = me.liveWidgets,\r
601 dataIndex = me.dataIndex,\r
602 isFixedSize = me.isFixedSize,\r
603 cell, widget, el, width, recordId,\r
604 itemIndex, recordIndex, record, id, lastBox, dom;\r
605\r
606 if (me.isVisible(true)) {\r
607 me.liveWidgets = {};\r
608 Ext.suspendLayouts();\r
609 for (itemIndex = rows.startIndex, recordIndex = 0; itemIndex <= rows.endIndex; itemIndex++, recordIndex++) {\r
610 record = records[recordIndex];\r
611 if (record.isNonData) {\r
612 continue;\r
613 }\r
614\r
615 recordId = record.internalId;\r
616 cell = view.getRow(rows.item(itemIndex)).cells[me.getVisibleIndex()].firstChild;\r
617\r
618 // Attempt to reuse the existing widget for this record.\r
619 widget = me.liveWidgets[recordId] = oldWidgetMap[recordId] || me.getFreeWidget();\r
620 widget.$widgetRecord = record;\r
621 widget.$widgetColumn = me;\r
622 delete oldWidgetMap[recordId];\r
623\r
624 lastBox = me.lastBox;\r
625 if (lastBox && !isFixedSize && width === undefined) {\r
626 width = lastBox.width - parseInt(me.getCachedStyle(cell, 'padding-left'), 10) - parseInt(me.getCachedStyle(cell, 'padding-right'), 10);\r
627 }\r
628\r
629 // Call the appropriate setter with this column's data field\r
630 if (widget.defaultBindProperty && dataIndex) {\r
631 widget.setConfig(widget.defaultBindProperty, records[recordIndex].get(dataIndex));\r
632 }\r
633 if (hasAttach) {\r
634 Ext.callback(me.onWidgetAttach, me.scope, [me, widget, record], 0, me);\r
635 }\r
636\r
637 el = widget.el || widget.element;\r
638 if (el) {\r
639 dom = el.dom;\r
640 if (dom.parentNode !== cell) {\r
641 Ext.fly(cell).empty();\r
642 cell.appendChild(el.dom);\r
643 }\r
644 if (!isFixedSize) {\r
645 widget.setWidth(width);\r
646 }\r
647 widget.reattachToBody();\r
648 } else {\r
649 if (!isFixedSize) {\r
650 widget.width = width;\r
651 }\r
652 Ext.fly(cell).empty();\r
653 widget.render(cell);\r
654 }\r
655 }\r
656\r
657 Ext.resumeLayouts(true);\r
658\r
659 // Free any unused widgets from the old live map.\r
660 // Move them into detachedBody.\r
661 for (id in oldWidgetMap) {\r
662 widget = oldWidgetMap[id];\r
663 widget.$widgetRecord = widget.$widgetColumn = null;\r
664 me.freeWidgetStack.unshift(widget);\r
665 widget.detachFromBody();\r
666 }\r
667 }\r
668 },\r
669\r
670 returnFalse: function() {\r
671 return false;\r
672 },\r
673\r
674 setupViewListeners: function(view) {\r
675 var me = this;\r
676\r
677 me.viewListeners = view.on({\r
678 refresh: me.onViewRefresh,\r
679 itemupdate: me.onItemUpdate,\r
680 itemadd: me.onItemAdd,\r
681 itemremove: me.onItemRemove,\r
682 scope: me,\r
683 destroyable: true\r
684 });\r
685\r
686 if (Ext.isIE8) {\r
687 view.on('beforerefresh', me.onBeforeRefresh, me);\r
688 }\r
689 },\r
690\r
691 updateWidget: function(record) {\r
692 var dataIndex = this.dataIndex,\r
693 widget;\r
694\r
695 if (this.rendered) {\r
696 widget = this.liveWidgets[record.internalId];\r
697 // Call the appropriate setter with this column's data field\r
698 if (widget && widget.defaultBindProperty && dataIndex) {\r
699 widget.setConfig(widget.defaultBindProperty, record.get(dataIndex));\r
700 }\r
701 }\r
702 }, \r
703 \r
704 widgetRecordDecorator: function() {\r
705 return this.$widgetRecord;\r
706 },\r
707 \r
708 widgetColumnDecorator: function() {\r
709 return this.$widgetColumn;\r
710 }\r
711 }\r
712});\r