Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / docs / source / AbstractView.html
1 <!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-view.AbstractView'>/**
2 </span> * @class Ext.view.AbstractView
3  * @extends Ext.Component
4  * This is an abstract superclass and should not be used directly. Please see {@link Ext.view.View}.
5  */
6 Ext.define('Ext.view.AbstractView', {
7     extend: 'Ext.Component',
8     alternateClassName: 'Ext.view.AbstractView',
9     requires: [
10         'Ext.LoadMask',
11         'Ext.data.StoreManager',
12         'Ext.CompositeElementLite',
13         'Ext.DomQuery',
14         'Ext.selection.DataViewModel'
15     ],
16     
17     inheritableStatics: {
18         getRecord: function(node) {
19             return this.getBoundView(node).getRecord(node);
20         },
21         
22         getBoundView: function(node) {
23             return Ext.getCmp(node.boundView);
24         }
25     },
26     
27 <span id='Ext-view.AbstractView-cfg-tpl'>    /**
28 </span>     * @cfg {String/Array/Ext.XTemplate} tpl
29      * @required
30      * The HTML fragment or an array of fragments that will make up the template used by this DataView.  This should
31      * be specified in the same format expected by the constructor of {@link Ext.XTemplate}.
32      */
33 <span id='Ext-view.AbstractView-cfg-store'>    /**
34 </span>     * @cfg {Ext.data.Store} store
35      * @required
36      * The {@link Ext.data.Store} to bind this DataView to.
37      */
38
39 <span id='Ext-view.AbstractView-cfg-itemSelector'>    /**
40 </span>     * @cfg {String} itemSelector
41      * @required
42      * &lt;b&gt;This is a required setting&lt;/b&gt;. A simple CSS selector (e.g. &lt;tt&gt;div.some-class&lt;/tt&gt; or
43      * &lt;tt&gt;span:first-child&lt;/tt&gt;) that will be used to determine what nodes this DataView will be
44      * working with. The itemSelector is used to map DOM nodes to records. As such, there should
45      * only be one root level element that matches the selector for each record.
46      */
47     
48 <span id='Ext-view.AbstractView-cfg-itemCls'>    /**
49 </span>     * @cfg {String} itemCls
50      * Specifies the class to be assigned to each element in the view when used in conjunction with the
51      * {@link #itemTpl} configuration.
52      */
53     itemCls: Ext.baseCSSPrefix + 'dataview-item',
54     
55 <span id='Ext-view.AbstractView-cfg-itemTpl'>    /**
56 </span>     * @cfg {String/Array/Ext.XTemplate} itemTpl
57      * The inner portion of the item template to be rendered. Follows an XTemplate
58      * structure and will be placed inside of a tpl.
59      */
60
61 <span id='Ext-view.AbstractView-cfg-overItemCls'>    /**
62 </span>     * @cfg {String} overItemCls
63      * A CSS class to apply to each item in the view on mouseover (defaults to undefined). 
64      * Ensure {@link #trackOver} is set to `true` to make use of this.
65      */
66
67 <span id='Ext-view.AbstractView-cfg-loadingText'>    /**
68 </span>     * @cfg {String} loadingText
69      * A string to display during data load operations (defaults to undefined).  If specified, this text will be
70      * displayed in a loading div and the view's contents will be cleared while loading, otherwise the view's
71      * contents will continue to display normally until the new data is loaded and the contents are replaced.
72      */
73     loadingText: 'Loading...',
74     
75 <span id='Ext-view.AbstractView-cfg-loadingCls'>    /**
76 </span>     * @cfg {String} loadingCls
77      * The CSS class to apply to the loading message element (defaults to Ext.LoadMask.prototype.msgCls &quot;x-mask-loading&quot;)
78      */
79     
80 <span id='Ext-view.AbstractView-cfg-loadingUseMsg'>    /**
81 </span>     * @cfg {Boolean} loadingUseMsg
82      * Whether or not to use the loading message.
83      * @private
84      */
85     loadingUseMsg: true,
86     
87
88 <span id='Ext-view.AbstractView-cfg-loadingHeight'>    /**
89 </span>     * @cfg {Number} loadingHeight
90      * If specified, gives an explicit height for the data view when it is showing the {@link #loadingText},
91      * if that is specified. This is useful to prevent the view's height from collapsing to zero when the
92      * loading mask is applied and there are no other contents in the data view. Defaults to undefined.
93      */
94
95 <span id='Ext-view.AbstractView-cfg-selectedItemCls'>    /**
96 </span>     * @cfg {String} selectedItemCls
97      * A CSS class to apply to each selected item in the view (defaults to 'x-view-selected').
98      */
99     selectedItemCls: Ext.baseCSSPrefix + 'item-selected',
100
101 <span id='Ext-view.AbstractView-cfg-emptyText'>    /**
102 </span>     * @cfg {String} emptyText
103      * The text to display in the view when there is no data to display (defaults to '').
104      * Note that when using local data the emptyText will not be displayed unless you set
105      * the {@link #deferEmptyText} option to false.
106      */
107     emptyText: &quot;&quot;,
108
109 <span id='Ext-view.AbstractView-cfg-deferEmptyText'>    /**
110 </span>     * @cfg {Boolean} deferEmptyText True to defer emptyText being applied until the store's first load
111      */
112     deferEmptyText: true,
113
114 <span id='Ext-view.AbstractView-cfg-trackOver'>    /**
115 </span>     * @cfg {Boolean} trackOver True to enable mouseenter and mouseleave events
116      */
117     trackOver: false,
118
119 <span id='Ext-view.AbstractView-cfg-blockRefresh'>    /**
120 </span>     * @cfg {Boolean} blockRefresh Set this to true to ignore datachanged events on the bound store. This is useful if
121      * you wish to provide custom transition animations via a plugin (defaults to false)
122      */
123     blockRefresh: false,
124
125 <span id='Ext-view.AbstractView-cfg-disableSelection'>    /**
126 </span>     * @cfg {Boolean} disableSelection &lt;p&gt;&lt;tt&gt;true&lt;/tt&gt; to disable selection within the DataView. Defaults to &lt;tt&gt;false&lt;/tt&gt;.
127      * This configuration will lock the selection model that the DataView uses.&lt;/p&gt;
128      */
129
130
131     //private
132     last: false,
133     
134     triggerEvent: 'itemclick',
135     triggerCtEvent: 'containerclick',
136     
137     addCmpEvents: function() {
138         
139     },
140
141     // private
142     initComponent : function(){
143         var me = this,
144             isDef = Ext.isDefined,
145             itemTpl = me.itemTpl,
146             memberFn = {};
147             
148         if (itemTpl) {
149             if (Ext.isArray(itemTpl)) {
150                 // string array
151                 itemTpl = itemTpl.join('');
152             } else if (Ext.isObject(itemTpl)) {
153                 // tpl instance
154                 memberFn = Ext.apply(memberFn, itemTpl.initialConfig);
155                 itemTpl = itemTpl.html;
156             }
157             
158             if (!me.itemSelector) {
159                 me.itemSelector = '.' + me.itemCls;
160             }
161             
162             itemTpl = Ext.String.format('&lt;tpl for=&quot;.&quot;&gt;&lt;div class=&quot;{0}&quot;&gt;{1}&lt;/div&gt;&lt;/tpl&gt;', me.itemCls, itemTpl);
163             me.tpl = Ext.create('Ext.XTemplate', itemTpl, memberFn);
164         }
165
166         //&lt;debug&gt;
167         if (!isDef(me.tpl) || !isDef(me.itemSelector)) {
168             Ext.Error.raise({
169                 sourceClass: 'Ext.view.View',
170                 tpl: me.tpl,
171                 itemSelector: me.itemSelector,
172                 msg: &quot;DataView requires both tpl and itemSelector configurations to be defined.&quot;
173             });
174         }
175         //&lt;/debug&gt;
176
177         me.callParent();
178         if(Ext.isString(me.tpl) || Ext.isArray(me.tpl)){
179             me.tpl = Ext.create('Ext.XTemplate', me.tpl);
180         }
181
182         //&lt;debug&gt;
183         // backwards compat alias for overClass/selectedClass
184         // TODO: Consider support for overCls generation Ext.Component config
185         if (isDef(me.overCls) || isDef(me.overClass)) {
186             if (Ext.isDefined(Ext.global.console)) {
187                 Ext.global.console.warn('Ext.view.View: Using the deprecated overCls or overClass configuration. Use overItemCls instead.');
188             }
189             me.overItemCls = me.overCls || me.overClass;
190             delete me.overCls;
191             delete me.overClass;
192         }
193
194         if (me.overItemCls) {
195             me.trackOver = true;
196         }
197         
198         if (isDef(me.selectedCls) || isDef(me.selectedClass)) {
199             if (Ext.isDefined(Ext.global.console)) {
200                 Ext.global.console.warn('Ext.view.View: Using the deprecated selectedCls or selectedClass configuration. Use selectedItemCls instead.');
201             }
202             me.selectedItemCls = me.selectedCls || me.selectedClass;
203             delete me.selectedCls;
204             delete me.selectedClass;
205         }
206         //&lt;/debug&gt;
207         
208         me.addEvents(
209 <span id='Ext-view.AbstractView-event-beforerefresh'>            /**
210 </span>             * @event beforerefresh
211              * Fires before the view is refreshed
212              * @param {Ext.view.View} this The DataView object
213              */
214             'beforerefresh',
215 <span id='Ext-view.AbstractView-event-refresh'>            /**
216 </span>             * @event refresh
217              * Fires when the view is refreshed
218              * @param {Ext.view.View} this The DataView object
219              */
220             'refresh',
221 <span id='Ext-view.AbstractView-event-itemupdate'>            /**
222 </span>             * @event itemupdate
223              * Fires when the node associated with an individual record is updated
224              * @param {Ext.data.Model} record The model instance
225              * @param {Number} index The index of the record/node
226              * @param {HTMLElement} node The node that has just been updated
227              */
228             'itemupdate',
229 <span id='Ext-view.AbstractView-event-itemadd'>            /**
230 </span>             * @event itemadd
231              * Fires when the nodes associated with an recordset have been added to the underlying store
232              * @param {Array[Ext.data.Model]} records The model instance
233              * @param {Number} index The index at which the set of record/nodes starts
234              * @param {Array[HTMLElement]} node The node that has just been updated
235              */
236             'itemadd',
237 <span id='Ext-view.AbstractView-event-itemremove'>            /**
238 </span>             * @event itemremove
239              * Fires when the node associated with an individual record is removed
240              * @param {Ext.data.Model} record The model instance
241              * @param {Number} index The index of the record/node
242              */
243             'itemremove'
244         );
245
246         me.addCmpEvents();
247
248         if (me.store) {
249             me.store = Ext.data.StoreManager.lookup(me.store);
250         }
251         me.all = new Ext.CompositeElementLite();
252         me.getSelectionModel().bindComponent(me);
253     },
254
255     onRender: function() {
256         var me = this,
257             loadingText = me.loadingText,
258             loadingHeight = me.loadingHeight,
259             undef;
260
261         me.callParent(arguments);
262         if (loadingText) {
263             
264             // Attach the LoadMask to a *Component* so that it can be sensitive to resizing during long loads.
265             // If this DataView is floating, then mask this DataView.
266             // Otherwise, mask its owning Container (or this, if there *is* no owning Container).
267             // LoadMask captures the element upon render.
268             me.loadMask = Ext.create('Ext.LoadMask', me.floating ? me : me.ownerCt || me, {
269                 msg: loadingText,
270                 msgCls: me.loadingCls,
271                 useMsg: me.loadingUseMsg,
272                 listeners: {
273                     beforeshow: function() {
274                         me.getTargetEl().update('');
275                         me.getSelectionModel().deselectAll();
276                         me.all.clear();
277                         if (loadingHeight) {
278                             me.setCalculatedSize(undef, loadingHeight);
279                         }
280                     },
281                     hide: function() {
282                         if (loadingHeight) {
283                             me.setHeight(me.height);
284                         }
285                     }
286                 }
287             });
288         }
289     },
290
291     getSelectionModel: function(){
292         var me = this,
293             mode = 'SINGLE';
294
295         if (!me.selModel) {
296             me.selModel = {};
297         }
298
299         if (me.simpleSelect) {
300             mode = 'SIMPLE';
301         } else if (me.multiSelect) {
302             mode = 'MULTI';
303         }
304
305         Ext.applyIf(me.selModel, {
306             allowDeselect: me.allowDeselect,
307             mode: mode
308         });
309
310         if (!me.selModel.events) {
311             me.selModel = Ext.create('Ext.selection.DataViewModel', me.selModel);
312         }
313
314         if (!me.selModel.hasRelaySetup) {
315             me.relayEvents(me.selModel, ['selectionchange', 'beforeselect', 'select', 'deselect']);
316             me.selModel.hasRelaySetup = true;
317         }
318
319         // lock the selection model if user
320         // has disabled selection
321         if (me.disableSelection) {
322             me.selModel.locked = true;
323         }
324
325         return me.selModel;
326     },
327
328 <span id='Ext-view.AbstractView-method-refresh'>    /**
329 </span>     * Refreshes the view by reloading the data from the store and re-rendering the template.
330      */
331     refresh: function() {
332         var me = this,
333             el,
334             records;
335             
336         if (!me.rendered) {
337             return;
338         }
339         
340         me.fireEvent('beforerefresh', me);
341         el = me.getTargetEl();
342         records = me.store.getRange();
343
344         el.update('');
345         if (records.length &lt; 1) {
346             if (!me.deferEmptyText || me.hasSkippedEmptyText) {
347                 el.update(me.emptyText);
348             }
349             me.all.clear();
350         } else {
351             me.tpl.overwrite(el, me.collectData(records, 0));
352             me.all.fill(Ext.query(me.getItemSelector(), el.dom));
353             me.updateIndexes(0);
354         }
355         
356         me.selModel.refresh();
357         me.hasSkippedEmptyText = true;
358         me.fireEvent('refresh', me);
359     },
360
361 <span id='Ext-view.AbstractView-method-prepareData'>    /**
362 </span>     * Function which can be overridden to provide custom formatting for each Record that is used by this
363      * DataView's {@link #tpl template} to render each node.
364      * @param {Array/Object} data The raw data object that was used to create the Record.
365      * @param {Number} recordIndex the index number of the Record being prepared for rendering.
366      * @param {Record} record The Record being prepared for rendering.
367      * @return {Array/Object} The formatted data in a format expected by the internal {@link #tpl template}'s overwrite() method.
368      * (either an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'}))
369      */
370     prepareData: function(data, index, record) {
371         if (record) {    
372             Ext.apply(data, record.getAssociatedData());            
373         }
374         return data;
375     },
376     
377 <span id='Ext-view.AbstractView-method-collectData'>    /**
378 </span>     * &lt;p&gt;Function which can be overridden which returns the data object passed to this
379      * DataView's {@link #tpl template} to render the whole DataView.&lt;/p&gt;
380      * &lt;p&gt;This is usually an Array of data objects, each element of which is processed by an
381      * {@link Ext.XTemplate XTemplate} which uses &lt;tt&gt;'&amp;lt;tpl for=&quot;.&quot;&amp;gt;'&lt;/tt&gt; to iterate over its supplied
382      * data object as an Array. However, &lt;i&gt;named&lt;/i&gt; properties may be placed into the data object to
383      * provide non-repeating data such as headings, totals etc.&lt;/p&gt;
384      * @param {Array} records An Array of {@link Ext.data.Model}s to be rendered into the DataView.
385      * @param {Number} startIndex the index number of the Record being prepared for rendering.
386      * @return {Array} An Array of data objects to be processed by a repeating XTemplate. May also
387      * contain &lt;i&gt;named&lt;/i&gt; properties.
388      */
389     collectData : function(records, startIndex){
390         var r = [],
391             i = 0,
392             len = records.length;
393
394         for(; i &lt; len; i++){
395             r[r.length] = this.prepareData(records[i].data, startIndex + i, records[i]);
396         }
397
398         return r;
399     },
400
401     // private
402     bufferRender : function(records, index){
403         var div = document.createElement('div');
404         this.tpl.overwrite(div, this.collectData(records, index));
405         return Ext.query(this.getItemSelector(), div);
406     },
407
408     // private
409     onUpdate : function(ds, record){
410         var me = this,
411             index = me.store.indexOf(record),
412             original,
413             node;
414
415         if (index &gt; -1){
416             original = me.all.elements[index];
417             node = me.bufferRender([record], index)[0];
418
419             me.all.replaceElement(index, node, true);
420             me.updateIndexes(index, index);
421
422             // Maintain selection after update
423             // TODO: Move to approriate event handler.
424             me.selModel.refresh();
425             me.fireEvent('itemupdate', record, index, node);
426         }
427
428     },
429
430     // private
431     onAdd : function(ds, records, index) {
432         var me = this,
433             nodes;
434             
435         if (me.all.getCount() === 0) {
436             me.refresh();
437             return;
438         }
439         
440         nodes = me.bufferRender(records, index);
441         me.doAdd(nodes, records, index);
442
443         me.selModel.refresh();
444         me.updateIndexes(index);
445         me.fireEvent('itemadd', records, index, nodes);
446     },
447
448     doAdd: function(nodes, records, index) {
449         var n, a = this.all.elements;
450         if (index &lt; this.all.getCount()) {
451             n = this.all.item(index).insertSibling(nodes, 'before', true);
452             a.splice.apply(a, [index, 0].concat(nodes));
453         } 
454         else {
455             n = this.all.last().insertSibling(nodes, 'after', true);
456             a.push.apply(a, nodes);
457         }    
458     },
459     
460     // private
461     onRemove : function(ds, record, index) {
462         var me = this;
463         
464         me.doRemove(record, index);
465         me.updateIndexes(index);
466         if (me.store.getCount() === 0){
467             me.refresh();
468         }
469         me.fireEvent('itemremove', record, index);
470     },
471     
472     doRemove: function(record, index) {
473         this.all.removeElement(index, true);
474     },
475
476 <span id='Ext-view.AbstractView-method-refreshNode'>    /**
477 </span>     * Refreshes an individual node's data from the store.
478      * @param {Number} index The item's data index in the store
479      */
480     refreshNode : function(index){
481         this.onUpdate(this.store, this.store.getAt(index));
482     },
483
484     // private
485     updateIndexes : function(startIndex, endIndex) {
486         var ns = this.all.elements,
487             records = this.store.getRange();
488         startIndex = startIndex || 0;
489         endIndex = endIndex || ((endIndex === 0) ? 0 : (ns.length - 1));
490         for(var i = startIndex; i &lt;= endIndex; i++){
491             ns[i].viewIndex = i;
492             ns[i].viewRecordId = records[i].internalId;
493             if (!ns[i].boundView) {
494                 ns[i].boundView = this.id;
495             }
496         }
497     },
498
499 <span id='Ext-view.AbstractView-method-getStore'>    /**
500 </span>     * Returns the store associated with this DataView.
501      * @return {Ext.data.Store} The store
502      */
503     getStore : function(){
504         return this.store;
505     },
506
507 <span id='Ext-view.AbstractView-method-bindStore'>    /**
508 </span>     * Changes the data store bound to this view and refreshes it.
509      * @param {Store} store The store to bind to this view
510      */
511     bindStore : function(store, initial) {
512         var me = this;
513         
514         if (!initial &amp;&amp; me.store) {
515             if (store !== me.store &amp;&amp; me.store.autoDestroy) {
516                 me.store.destroy();
517             } 
518             else {
519                 me.mun(me.store, {
520                     scope: me,
521                     datachanged: me.onDataChanged,
522                     add: me.onAdd,
523                     remove: me.onRemove,
524                     update: me.onUpdate,
525                     clear: me.refresh
526                 });
527             }
528             if (!store) {
529                 if (me.loadMask) {
530                     me.loadMask.bindStore(null);
531                 }
532                 me.store = null;
533             }
534         }
535         if (store) {
536             store = Ext.data.StoreManager.lookup(store);
537             me.mon(store, {
538                 scope: me,
539                 datachanged: me.onDataChanged,
540                 add: me.onAdd,
541                 remove: me.onRemove,
542                 update: me.onUpdate,
543                 clear: me.refresh
544             });
545             if (me.loadMask) {
546                 me.loadMask.bindStore(store);
547             }
548         }
549         
550         me.store = store;
551         // Bind the store to our selection model
552         me.getSelectionModel().bind(store);
553         
554         if (store) {
555             me.refresh(true);
556         }
557     },
558
559 <span id='Ext-view.AbstractView-method-onDataChanged'>    /**
560 </span>     * @private
561      * Calls this.refresh if this.blockRefresh is not true
562      */
563     onDataChanged: function() {
564         if (this.blockRefresh !== true) {
565             this.refresh.apply(this, arguments);
566         }
567     },
568
569 <span id='Ext-view.AbstractView-method-findItemByChild'>    /**
570 </span>     * Returns the template node the passed child belongs to, or null if it doesn't belong to one.
571      * @param {HTMLElement} node
572      * @return {HTMLElement} The template node
573      */
574     findItemByChild: function(node){
575         return Ext.fly(node).findParent(this.getItemSelector(), this.getTargetEl());
576     },
577     
578 <span id='Ext-view.AbstractView-method-findTargetByEvent'>    /**
579 </span>     * Returns the template node by the Ext.EventObject or null if it is not found.
580      * @param {Ext.EventObject} e
581      */
582     findTargetByEvent: function(e) {
583         return e.getTarget(this.getItemSelector(), this.getTargetEl());
584     },
585
586
587 <span id='Ext-view.AbstractView-method-getSelectedNodes'>    /**
588 </span>     * Gets the currently selected nodes.
589      * @return {Array} An array of HTMLElements
590      */
591     getSelectedNodes: function(){
592         var nodes   = [],
593             records = this.selModel.getSelection(),
594             ln = records.length,
595             i  = 0;
596
597         for (; i &lt; ln; i++) {
598             nodes.push(this.getNode(records[i]));
599         }
600
601         return nodes;
602     },
603
604 <span id='Ext-view.AbstractView-method-getRecords'>    /**
605 </span>     * Gets an array of the records from an array of nodes
606      * @param {Array} nodes The nodes to evaluate
607      * @return {Array} records The {@link Ext.data.Model} objects
608      */
609     getRecords: function(nodes) {
610         var records = [],
611             i = 0,
612             len = nodes.length,
613             data = this.store.data;
614
615         for (; i &lt; len; i++) {
616             records[records.length] = data.getByKey(nodes[i].viewRecordId);
617         }
618
619         return records;
620     },
621
622 <span id='Ext-view.AbstractView-method-getRecord'>    /**
623 </span>     * Gets a record from a node
624      * @param {Element/HTMLElement} node The node to evaluate
625      * 
626      * @return {Record} record The {@link Ext.data.Model} object
627      */
628     getRecord: function(node){
629         return this.store.data.getByKey(Ext.getDom(node).viewRecordId);
630     },
631     
632
633 <span id='Ext-view.AbstractView-method-isSelected'>    /**
634 </span>     * Returns true if the passed node is selected, else false.
635      * @param {HTMLElement/Number/Ext.data.Model} node The node, node index or record to check
636      * @return {Boolean} True if selected, else false
637      */
638     isSelected : function(node) {
639         // TODO: El/Idx/Record
640         var r = this.getRecord(node);
641         return this.selModel.isSelected(r);
642     },
643     
644 <span id='Ext-view.AbstractView-method-select'>    /**
645 </span>     * Selects a record instance by record instance or index.
646      * @param {Ext.data.Model/Index} records An array of records or an index
647      * @param {Boolean} keepExisting
648      * @param {Boolean} suppressEvent Set to false to not fire a select event
649      */
650     select: function(records, keepExisting, suppressEvent) {
651         this.selModel.select(records, keepExisting, suppressEvent);
652     },
653
654 <span id='Ext-view.AbstractView-method-deselect'>    /**
655 </span>     * Deselects a record instance by record instance or index.
656      * @param {Ext.data.Model/Index} records An array of records or an index
657      * @param {Boolean} suppressEvent Set to false to not fire a deselect event
658      */
659     deselect: function(records, suppressEvent) {
660         this.selModel.deselect(records, suppressEvent);
661     },
662
663 <span id='Ext-view.AbstractView-method-getNode'>    /**
664 </span>     * Gets a template node.
665      * @param {HTMLElement/String/Number/Ext.data.Model} nodeInfo An HTMLElement template node, index of a template node,
666      * the id of a template node or the record associated with the node.
667      * @return {HTMLElement} The node or null if it wasn't found
668      */
669     getNode : function(nodeInfo) {
670         if (Ext.isString(nodeInfo)) {
671             return document.getElementById(nodeInfo);
672         } else if (Ext.isNumber(nodeInfo)) {
673             return this.all.elements[nodeInfo];
674         } else if (nodeInfo instanceof Ext.data.Model) {
675             return this.getNodeByRecord(nodeInfo);
676         }
677         return nodeInfo;
678     },
679     
680 <span id='Ext-view.AbstractView-method-getNodeByRecord'>    /**
681 </span>     * @private
682      */
683     getNodeByRecord: function(record) {
684         var ns = this.all.elements,
685             ln = ns.length,
686             i = 0;
687         
688         for (; i &lt; ln; i++) {
689             if (ns[i].viewRecordId === record.internalId) {
690                 return ns[i];
691             }
692         }
693         
694         return null;
695     },
696     
697 <span id='Ext-view.AbstractView-method-getNodes'>    /**
698 </span>     * Gets a range nodes.
699      * @param {Number} start (optional) The index of the first node in the range
700      * @param {Number} end (optional) The index of the last node in the range
701      * @return {Array} An array of nodes
702      */
703     getNodes: function(start, end) {
704         var ns = this.all.elements,
705             nodes = [],
706             i;
707
708         start = start || 0;
709         end = !Ext.isDefined(end) ? Math.max(ns.length - 1, 0) : end;
710         if (start &lt;= end) {
711             for (i = start; i &lt;= end &amp;&amp; ns[i]; i++) {
712                 nodes.push(ns[i]);
713             }
714         } else {
715             for (i = start; i &gt;= end &amp;&amp; ns[i]; i--) {
716                 nodes.push(ns[i]);
717             }
718         }
719         return nodes;
720     },
721
722 <span id='Ext-view.AbstractView-method-indexOf'>    /**
723 </span>     * Finds the index of the passed node.
724      * @param {HTMLElement/String/Number/Record} nodeInfo An HTMLElement template node, index of a template node, the id of a template node
725      * or a record associated with a node.
726      * @return {Number} The index of the node or -1
727      */
728     indexOf: function(node) {
729         node = this.getNode(node);
730         if (Ext.isNumber(node.viewIndex)) {
731             return node.viewIndex;
732         }
733         return this.all.indexOf(node);
734     },
735
736     onDestroy : function() {
737         var me = this;
738         
739         me.all.clear();
740         me.callParent();
741         me.bindStore(null);
742         me.selModel.destroy();
743     },
744
745     // invoked by the selection model to maintain visual UI cues
746     onItemSelect: function(record) {
747         var node = this.getNode(record);
748         Ext.fly(node).addCls(this.selectedItemCls);
749     },
750
751     // invoked by the selection model to maintain visual UI cues
752     onItemDeselect: function(record) {
753         var node = this.getNode(record);
754         Ext.fly(node).removeCls(this.selectedItemCls);
755     },
756     
757     getItemSelector: function() {
758         return this.itemSelector;
759     }
760 }, function() {
761     // all of this information is available directly
762     // from the SelectionModel itself, the only added methods
763     // to DataView regarding selection will perform some transformation/lookup
764     // between HTMLElement/Nodes to records and vice versa.
765     Ext.deprecate('extjs', '4.0', function() {
766         Ext.view.AbstractView.override({
767 <span id='Ext-view.AbstractView-cfg-multiSelect'>            /**
768 </span>             * @cfg {Boolean} multiSelect
769              * True to allow selection of more than one item at a time, false to allow selection of only a single item
770              * at a time or no selection at all, depending on the value of {@link #singleSelect} (defaults to false).
771              */
772 <span id='Ext-view.AbstractView-cfg-singleSelect'>            /**
773 </span>             * @cfg {Boolean} singleSelect
774              * True to allow selection of exactly one item at a time, false to allow no selection at all (defaults to false).
775              * Note that if {@link #multiSelect} = true, this value will be ignored.
776              */
777 <span id='Ext-view.AbstractView-cfg-simpleSelect'>            /**
778 </span>             * @cfg {Boolean} simpleSelect
779              * True to enable multiselection by clicking on multiple items without requiring the user to hold Shift or Ctrl,
780              * false to force the user to hold Ctrl or Shift to select more than on item (defaults to false).
781              */
782             
783 <span id='Ext-view.AbstractView-method-getSelectionCount'>            /**
784 </span>             * Gets the number of selected nodes.
785              * @return {Number} The node count
786              */
787             getSelectionCount : function(){
788                 console.warn(&quot;DataView: getSelectionCount will be removed, please interact with the Ext.selection.DataViewModel&quot;);
789                 return this.selModel.getSelection().length;
790             },
791         
792 <span id='Ext-view.AbstractView-method-getSelectedRecords'>            /**
793 </span>             * Gets an array of the selected records
794              * @return {Array} An array of {@link Ext.data.Model} objects
795              */
796             getSelectedRecords : function(){
797                 console.warn(&quot;DataView: getSelectedRecords will be removed, please interact with the Ext.selection.DataViewModel&quot;);
798                 return this.selModel.getSelection();
799             },
800     
801             select: function(records, keepExisting, supressEvents) {
802                 console.warn(&quot;DataView: select will be removed, please access select through a DataView's SelectionModel, ie: view.getSelectionModel().select()&quot;);
803                 var sm = this.getSelectionModel();
804                 return sm.select.apply(sm, arguments);
805             },
806             
807             clearSelections: function() {
808                 console.warn(&quot;DataView: clearSelections will be removed, please access deselectAll through DataView's SelectionModel, ie: view.getSelectionModel().deselectAll()&quot;);
809                 var sm = this.getSelectionModel();
810                 return sm.deselectAll();
811             }
812         });    
813     });
814 });
815 </pre></pre></body></html>