Upgrade to ExtJS 3.3.1 - Released 11/30/2010
[extjs.git] / docs / source / DataView.html
1 <html>
2 <head>
3   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    
4   <title>The source code</title>
5     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
6     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
7 </head>
8 <body  onload="prettyPrint();">
9     <pre class="prettyprint lang-js">/*!
10  * Ext JS Library 3.3.1
11  * Copyright(c) 2006-2010 Sencha Inc.
12  * licensing@sencha.com
13  * http://www.sencha.com/license
14  */
15 <div id="cls-Ext.DataView"></div>/**
16  * @class Ext.DataView
17  * @extends Ext.BoxComponent
18  * A mechanism for displaying data using custom layout templates and formatting. DataView uses an {@link Ext.XTemplate}
19  * as its internal templating mechanism, and is bound to an {@link Ext.data.Store}
20  * so that as the data in the store changes the view is automatically updated to reflect the changes.  The view also
21  * provides built-in behavior for many common events that can occur for its contained items including click, doubleclick,
22  * mouseover, mouseout, etc. as well as a built-in selection model. <b>In order to use these features, an {@link #itemSelector}
23  * config must be provided for the DataView to determine what nodes it will be working with.</b>
24  *
25  * <p>The example below binds a DataView to a {@link Ext.data.Store} and renders it into an {@link Ext.Panel}.</p>
26  * <pre><code>
27 var store = new Ext.data.JsonStore({
28     url: 'get-images.php',
29     root: 'images',
30     fields: [
31         'name', 'url',
32         {name:'size', type: 'float'},
33         {name:'lastmod', type:'date', dateFormat:'timestamp'}
34     ]
35 });
36 store.load();
37
38 var tpl = new Ext.XTemplate(
39     '&lt;tpl for="."&gt;',
40         '&lt;div class="thumb-wrap" id="{name}"&gt;',
41         '&lt;div class="thumb"&gt;&lt;img src="{url}" title="{name}"&gt;&lt;/div&gt;',
42         '&lt;span class="x-editable"&gt;{shortName}&lt;/span&gt;&lt;/div&gt;',
43     '&lt;/tpl&gt;',
44     '&lt;div class="x-clear"&gt;&lt;/div&gt;'
45 );
46
47 var panel = new Ext.Panel({
48     id:'images-view',
49     frame:true,
50     width:535,
51     autoHeight:true,
52     collapsible:true,
53     layout:'fit',
54     title:'Simple DataView',
55
56     items: new Ext.DataView({
57         store: store,
58         tpl: tpl,
59         autoHeight:true,
60         multiSelect: true,
61         overClass:'x-view-over',
62         itemSelector:'div.thumb-wrap',
63         emptyText: 'No images to display'
64     })
65 });
66 panel.render(document.body);
67 </code></pre>
68  * @constructor
69  * Create a new DataView
70  * @param {Object} config The config object
71  * @xtype dataview
72  */
73 Ext.DataView = Ext.extend(Ext.BoxComponent, {
74     <div id="cfg-Ext.DataView-tpl"></div>/**
75      * @cfg {String/Array} tpl
76      * The HTML fragment or an array of fragments that will make up the template used by this DataView.  This should
77      * be specified in the same format expected by the constructor of {@link Ext.XTemplate}.
78      */
79     <div id="cfg-Ext.DataView-store"></div>/**
80      * @cfg {Ext.data.Store} store
81      * The {@link Ext.data.Store} to bind this DataView to.
82      */
83     <div id="cfg-Ext.DataView-itemSelector"></div>/**
84      * @cfg {String} itemSelector
85      * <b>This is a required setting</b>. A simple CSS selector (e.g. <tt>div.some-class</tt> or 
86      * <tt>span:first-child</tt>) that will be used to determine what nodes this DataView will be
87      * working with.
88      */
89     <div id="cfg-Ext.DataView-multiSelect"></div>/**
90      * @cfg {Boolean} multiSelect
91      * True to allow selection of more than one item at a time, false to allow selection of only a single item
92      * at a time or no selection at all, depending on the value of {@link #singleSelect} (defaults to false).
93      */
94     <div id="cfg-Ext.DataView-singleSelect"></div>/**
95      * @cfg {Boolean} singleSelect
96      * True to allow selection of exactly one item at a time, false to allow no selection at all (defaults to false).
97      * Note that if {@link #multiSelect} = true, this value will be ignored.
98      */
99     <div id="cfg-Ext.DataView-simpleSelect"></div>/**
100      * @cfg {Boolean} simpleSelect
101      * True to enable multiselection by clicking on multiple items without requiring the user to hold Shift or Ctrl,
102      * false to force the user to hold Ctrl or Shift to select more than on item (defaults to false).
103      */
104     <div id="cfg-Ext.DataView-overClass"></div>/**
105      * @cfg {String} overClass
106      * A CSS class to apply to each item in the view on mouseover (defaults to undefined).
107      */
108     <div id="cfg-Ext.DataView-loadingText"></div>/**
109      * @cfg {String} loadingText
110      * A string to display during data load operations (defaults to undefined).  If specified, this text will be
111      * displayed in a loading div and the view's contents will be cleared while loading, otherwise the view's
112      * contents will continue to display normally until the new data is loaded and the contents are replaced.
113      */
114     <div id="cfg-Ext.DataView-selectedClass"></div>/**
115      * @cfg {String} selectedClass
116      * A CSS class to apply to each selected item in the view (defaults to 'x-view-selected').
117      */
118     selectedClass : "x-view-selected",
119     <div id="cfg-Ext.DataView-emptyText"></div>/**
120      * @cfg {String} emptyText
121      * The text to display in the view when there is no data to display (defaults to '').
122      */
123     emptyText : "",
124
125     <div id="cfg-Ext.DataView-deferEmptyText"></div>/**
126      * @cfg {Boolean} deferEmptyText True to defer emptyText being applied until the store's first load
127      */
128     deferEmptyText: true,
129     <div id="cfg-Ext.DataView-trackOver"></div>/**
130      * @cfg {Boolean} trackOver True to enable mouseenter and mouseleave events
131      */
132     trackOver: false,
133     
134     <div id="cfg-Ext.DataView-blockRefresh"></div>/**
135      * @cfg {Boolean} blockRefresh Set this to true to ignore datachanged events on the bound store. This is useful if
136      * you wish to provide custom transition animations via a plugin (defaults to false)
137      */
138     blockRefresh: false,
139
140     //private
141     last: false,
142
143     // private
144     initComponent : function(){
145         Ext.DataView.superclass.initComponent.call(this);
146         if(Ext.isString(this.tpl) || Ext.isArray(this.tpl)){
147             this.tpl = new Ext.XTemplate(this.tpl);
148         }
149
150         this.addEvents(
151             <div id="event-Ext.DataView-beforeclick"></div>/**
152              * @event beforeclick
153              * Fires before a click is processed. Returns false to cancel the default action.
154              * @param {Ext.DataView} this
155              * @param {Number} index The index of the target node
156              * @param {HTMLElement} node The target node
157              * @param {Ext.EventObject} e The raw event object
158              */
159             "beforeclick",
160             <div id="event-Ext.DataView-click"></div>/**
161              * @event click
162              * Fires when a template node is clicked.
163              * @param {Ext.DataView} this
164              * @param {Number} index The index of the target node
165              * @param {HTMLElement} node The target node
166              * @param {Ext.EventObject} e The raw event object
167              */
168             "click",
169             <div id="event-Ext.DataView-mouseenter"></div>/**
170              * @event mouseenter
171              * Fires when the mouse enters a template node. trackOver:true or an overClass must be set to enable this event.
172              * @param {Ext.DataView} this
173              * @param {Number} index The index of the target node
174              * @param {HTMLElement} node The target node
175              * @param {Ext.EventObject} e The raw event object
176              */
177             "mouseenter",
178             <div id="event-Ext.DataView-mouseleave"></div>/**
179              * @event mouseleave
180              * Fires when the mouse leaves a template node. trackOver:true or an overClass must be set to enable this event.
181              * @param {Ext.DataView} this
182              * @param {Number} index The index of the target node
183              * @param {HTMLElement} node The target node
184              * @param {Ext.EventObject} e The raw event object
185              */
186             "mouseleave",
187             <div id="event-Ext.DataView-containerclick"></div>/**
188              * @event containerclick
189              * Fires when a click occurs and it is not on a template node.
190              * @param {Ext.DataView} this
191              * @param {Ext.EventObject} e The raw event object
192              */
193             "containerclick",
194             <div id="event-Ext.DataView-dblclick"></div>/**
195              * @event dblclick
196              * Fires when a template node is double clicked.
197              * @param {Ext.DataView} this
198              * @param {Number} index The index of the target node
199              * @param {HTMLElement} node The target node
200              * @param {Ext.EventObject} e The raw event object
201              */
202             "dblclick",
203             <div id="event-Ext.DataView-contextmenu"></div>/**
204              * @event contextmenu
205              * Fires when a template node is right clicked.
206              * @param {Ext.DataView} this
207              * @param {Number} index The index of the target node
208              * @param {HTMLElement} node The target node
209              * @param {Ext.EventObject} e The raw event object
210              */
211             "contextmenu",
212             <div id="event-Ext.DataView-containercontextmenu"></div>/**
213              * @event containercontextmenu
214              * Fires when a right click occurs that is not on a template node.
215              * @param {Ext.DataView} this
216              * @param {Ext.EventObject} e The raw event object
217              */
218             "containercontextmenu",
219             <div id="event-Ext.DataView-selectionchange"></div>/**
220              * @event selectionchange
221              * Fires when the selected nodes change.
222              * @param {Ext.DataView} this
223              * @param {Array} selections Array of the selected nodes
224              */
225             "selectionchange",
226
227             <div id="event-Ext.DataView-beforeselect"></div>/**
228              * @event beforeselect
229              * Fires before a selection is made. If any handlers return false, the selection is cancelled.
230              * @param {Ext.DataView} this
231              * @param {HTMLElement} node The node to be selected
232              * @param {Array} selections Array of currently selected nodes
233              */
234             "beforeselect"
235         );
236
237         this.store = Ext.StoreMgr.lookup(this.store);
238         this.all = new Ext.CompositeElementLite();
239         this.selected = new Ext.CompositeElementLite();
240     },
241
242     // private
243     afterRender : function(){
244         Ext.DataView.superclass.afterRender.call(this);
245
246                 this.mon(this.getTemplateTarget(), {
247             "click": this.onClick,
248             "dblclick": this.onDblClick,
249             "contextmenu": this.onContextMenu,
250             scope:this
251         });
252
253         if(this.overClass || this.trackOver){
254             this.mon(this.getTemplateTarget(), {
255                 "mouseover": this.onMouseOver,
256                 "mouseout": this.onMouseOut,
257                 scope:this
258             });
259         }
260
261         if(this.store){
262             this.bindStore(this.store, true);
263         }
264     },
265
266     <div id="method-Ext.DataView-refresh"></div>/**
267      * Refreshes the view by reloading the data from the store and re-rendering the template.
268      */
269     refresh : function() {
270         this.clearSelections(false, true);
271         var el = this.getTemplateTarget(),
272             records = this.store.getRange();
273             
274         el.update('');
275         if(records.length < 1){
276             if(!this.deferEmptyText || this.hasSkippedEmptyText){
277                 el.update(this.emptyText);
278             }
279             this.all.clear();
280         }else{
281             this.tpl.overwrite(el, this.collectData(records, 0));
282             this.all.fill(Ext.query(this.itemSelector, el.dom));
283             this.updateIndexes(0);
284         }
285         this.hasSkippedEmptyText = true;
286     },
287
288     getTemplateTarget: function(){
289         return this.el;
290     },
291
292     <div id="method-Ext.DataView-prepareData"></div>/**
293      * Function which can be overridden to provide custom formatting for each Record that is used by this
294      * DataView's {@link #tpl template} to render each node.
295      * @param {Array/Object} data The raw data object that was used to create the Record.
296      * @param {Number} recordIndex the index number of the Record being prepared for rendering.
297      * @param {Record} record The Record being prepared for rendering.
298      * @return {Array/Object} The formatted data in a format expected by the internal {@link #tpl template}'s overwrite() method.
299      * (either an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'}))
300      */
301     prepareData : function(data){
302         return data;
303     },
304
305     <div id="method-Ext.DataView-collectData"></div>/**
306      * <p>Function which can be overridden which returns the data object passed to this
307      * DataView's {@link #tpl template} to render the whole DataView.</p>
308      * <p>This is usually an Array of data objects, each element of which is processed by an
309      * {@link Ext.XTemplate XTemplate} which uses <tt>'&lt;tpl for="."&gt;'</tt> to iterate over its supplied
310      * data object as an Array. However, <i>named</i> properties may be placed into the data object to
311      * provide non-repeating data such as headings, totals etc.</p>
312      * @param {Array} records An Array of {@link Ext.data.Record}s to be rendered into the DataView.
313      * @param {Number} startIndex the index number of the Record being prepared for rendering.
314      * @return {Array} An Array of data objects to be processed by a repeating XTemplate. May also
315      * contain <i>named</i> properties.
316      */
317     collectData : function(records, startIndex){
318         var r = [],
319             i = 0,
320             len = records.length;
321         for(; i < len; i++){
322             r[r.length] = this.prepareData(records[i].data, startIndex + i, records[i]);
323         }
324         return r;
325     },
326
327     // private
328     bufferRender : function(records, index){
329         var div = document.createElement('div');
330         this.tpl.overwrite(div, this.collectData(records, index));
331         return Ext.query(this.itemSelector, div);
332     },
333
334     // private
335     onUpdate : function(ds, record){
336         var index = this.store.indexOf(record);
337         if(index > -1){
338             var sel = this.isSelected(index),
339                 original = this.all.elements[index],
340                 node = this.bufferRender([record], index)[0];
341
342             this.all.replaceElement(index, node, true);
343             if(sel){
344                 this.selected.replaceElement(original, node);
345                 this.all.item(index).addClass(this.selectedClass);
346             }
347             this.updateIndexes(index, index);
348         }
349     },
350
351     // private
352     onAdd : function(ds, records, index){
353         if(this.all.getCount() === 0){
354             this.refresh();
355             return;
356         }
357         var nodes = this.bufferRender(records, index), n, a = this.all.elements;
358         if(index < this.all.getCount()){
359             n = this.all.item(index).insertSibling(nodes, 'before', true);
360             a.splice.apply(a, [index, 0].concat(nodes));
361         }else{
362             n = this.all.last().insertSibling(nodes, 'after', true);
363             a.push.apply(a, nodes);
364         }
365         this.updateIndexes(index);
366     },
367
368     // private
369     onRemove : function(ds, record, index){
370         this.deselect(index);
371         this.all.removeElement(index, true);
372         this.updateIndexes(index);
373         if (this.store.getCount() === 0){
374             this.refresh();
375         }
376     },
377
378     <div id="method-Ext.DataView-refreshNode"></div>/**
379      * Refreshes an individual node's data from the store.
380      * @param {Number} index The item's data index in the store
381      */
382     refreshNode : function(index){
383         this.onUpdate(this.store, this.store.getAt(index));
384     },
385
386     // private
387     updateIndexes : function(startIndex, endIndex){
388         var ns = this.all.elements;
389         startIndex = startIndex || 0;
390         endIndex = endIndex || ((endIndex === 0) ? 0 : (ns.length - 1));
391         for(var i = startIndex; i <= endIndex; i++){
392             ns[i].viewIndex = i;
393         }
394     },
395     
396     <div id="method-Ext.DataView-getStore"></div>/**
397      * Returns the store associated with this DataView.
398      * @return {Ext.data.Store} The store
399      */
400     getStore : function(){
401         return this.store;
402     },
403
404     <div id="method-Ext.DataView-bindStore"></div>/**
405      * Changes the data store bound to this view and refreshes it.
406      * @param {Store} store The store to bind to this view
407      */
408     bindStore : function(store, initial){
409         if(!initial && this.store){
410             if(store !== this.store && this.store.autoDestroy){
411                 this.store.destroy();
412             }else{
413                 this.store.un("beforeload", this.onBeforeLoad, this);
414                 this.store.un("datachanged", this.onDataChanged, this);
415                 this.store.un("add", this.onAdd, this);
416                 this.store.un("remove", this.onRemove, this);
417                 this.store.un("update", this.onUpdate, this);
418                 this.store.un("clear", this.refresh, this);
419             }
420             if(!store){
421                 this.store = null;
422             }
423         }
424         if(store){
425             store = Ext.StoreMgr.lookup(store);
426             store.on({
427                 scope: this,
428                 beforeload: this.onBeforeLoad,
429                 datachanged: this.onDataChanged,
430                 add: this.onAdd,
431                 remove: this.onRemove,
432                 update: this.onUpdate,
433                 clear: this.refresh
434             });
435         }
436         this.store = store;
437         if(store){
438             this.refresh();
439         }
440     },
441     
442     /**
443      * @private
444      * Calls this.refresh if this.blockRefresh is not true
445      */
446     onDataChanged: function() {
447         if (this.blockRefresh !== true) {
448             this.refresh.apply(this, arguments);
449         }
450     },
451
452     <div id="method-Ext.DataView-findItemFromChild"></div>/**
453      * Returns the template node the passed child belongs to, or null if it doesn't belong to one.
454      * @param {HTMLElement} node
455      * @return {HTMLElement} The template node
456      */
457     findItemFromChild : function(node){
458         return Ext.fly(node).findParent(this.itemSelector, this.getTemplateTarget());
459     },
460
461     // private
462     onClick : function(e){
463         var item = e.getTarget(this.itemSelector, this.getTemplateTarget()),
464             index;
465         if(item){
466             index = this.indexOf(item);
467             if(this.onItemClick(item, index, e) !== false){
468                 this.fireEvent("click", this, index, item, e);
469             }
470         }else{
471             if(this.fireEvent("containerclick", this, e) !== false){
472                 this.onContainerClick(e);
473             }
474         }
475     },
476
477     onContainerClick : function(e){
478         this.clearSelections();
479     },
480
481     // private
482     onContextMenu : function(e){
483         var item = e.getTarget(this.itemSelector, this.getTemplateTarget());
484         if(item){
485             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
486         }else{
487             this.fireEvent("containercontextmenu", this, e);
488         }
489     },
490
491     // private
492     onDblClick : function(e){
493         var item = e.getTarget(this.itemSelector, this.getTemplateTarget());
494         if(item){
495             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
496         }
497     },
498
499     // private
500     onMouseOver : function(e){
501         var item = e.getTarget(this.itemSelector, this.getTemplateTarget());
502         if(item && item !== this.lastItem){
503             this.lastItem = item;
504             Ext.fly(item).addClass(this.overClass);
505             this.fireEvent("mouseenter", this, this.indexOf(item), item, e);
506         }
507     },
508
509     // private
510     onMouseOut : function(e){
511         if(this.lastItem){
512             if(!e.within(this.lastItem, true, true)){
513                 Ext.fly(this.lastItem).removeClass(this.overClass);
514                 this.fireEvent("mouseleave", this, this.indexOf(this.lastItem), this.lastItem, e);
515                 delete this.lastItem;
516             }
517         }
518     },
519
520     // private
521     onItemClick : function(item, index, e){
522         if(this.fireEvent("beforeclick", this, index, item, e) === false){
523             return false;
524         }
525         if(this.multiSelect){
526             this.doMultiSelection(item, index, e);
527             e.preventDefault();
528         }else if(this.singleSelect){
529             this.doSingleSelection(item, index, e);
530             e.preventDefault();
531         }
532         return true;
533     },
534
535     // private
536     doSingleSelection : function(item, index, e){
537         if(e.ctrlKey && this.isSelected(index)){
538             this.deselect(index);
539         }else{
540             this.select(index, false);
541         }
542     },
543
544     // private
545     doMultiSelection : function(item, index, e){
546         if(e.shiftKey && this.last !== false){
547             var last = this.last;
548             this.selectRange(last, index, e.ctrlKey);
549             this.last = last; // reset the last
550         }else{
551             if((e.ctrlKey||this.simpleSelect) && this.isSelected(index)){
552                 this.deselect(index);
553             }else{
554                 this.select(index, e.ctrlKey || e.shiftKey || this.simpleSelect);
555             }
556         }
557     },
558
559     <div id="method-Ext.DataView-getSelectionCount"></div>/**
560      * Gets the number of selected nodes.
561      * @return {Number} The node count
562      */
563     getSelectionCount : function(){
564         return this.selected.getCount();
565     },
566
567     <div id="method-Ext.DataView-getSelectedNodes"></div>/**
568      * Gets the currently selected nodes.
569      * @return {Array} An array of HTMLElements
570      */
571     getSelectedNodes : function(){
572         return this.selected.elements;
573     },
574
575     <div id="method-Ext.DataView-getSelectedIndexes"></div>/**
576      * Gets the indexes of the selected nodes.
577      * @return {Array} An array of numeric indexes
578      */
579     getSelectedIndexes : function(){
580         var indexes = [], 
581             selected = this.selected.elements,
582             i = 0,
583             len = selected.length;
584             
585         for(; i < len; i++){
586             indexes.push(selected[i].viewIndex);
587         }
588         return indexes;
589     },
590
591     <div id="method-Ext.DataView-getSelectedRecords"></div>/**
592      * Gets an array of the selected records
593      * @return {Array} An array of {@link Ext.data.Record} objects
594      */
595     getSelectedRecords : function(){
596         return this.getRecords(this.selected.elements);
597     },
598
599     <div id="method-Ext.DataView-getRecords"></div>/**
600      * Gets an array of the records from an array of nodes
601      * @param {Array} nodes The nodes to evaluate
602      * @return {Array} records The {@link Ext.data.Record} objects
603      */
604     getRecords : function(nodes){
605         var records = [], 
606             i = 0,
607             len = nodes.length;
608             
609         for(; i < len; i++){
610             records[records.length] = this.store.getAt(nodes[i].viewIndex);
611         }
612         return records;
613     },
614
615     <div id="method-Ext.DataView-getRecord"></div>/**
616      * Gets a record from a node
617      * @param {HTMLElement} node The node to evaluate
618      * @return {Record} record The {@link Ext.data.Record} object
619      */
620     getRecord : function(node){
621         return this.store.getAt(node.viewIndex);
622     },
623
624     <div id="method-Ext.DataView-clearSelections"></div>/**
625      * Clears all selections.
626      * @param {Boolean} suppressEvent (optional) True to skip firing of the selectionchange event
627      */
628     clearSelections : function(suppressEvent, skipUpdate){
629         if((this.multiSelect || this.singleSelect) && this.selected.getCount() > 0){
630             if(!skipUpdate){
631                 this.selected.removeClass(this.selectedClass);
632             }
633             this.selected.clear();
634             this.last = false;
635             if(!suppressEvent){
636                 this.fireEvent("selectionchange", this, this.selected.elements);
637             }
638         }
639     },
640
641     <div id="method-Ext.DataView-isSelected"></div>/**
642      * Returns true if the passed node is selected, else false.
643      * @param {HTMLElement/Number/Ext.data.Record} node The node, node index or record to check
644      * @return {Boolean} True if selected, else false
645      */
646     isSelected : function(node){
647         return this.selected.contains(this.getNode(node));
648     },
649
650     <div id="method-Ext.DataView-deselect"></div>/**
651      * Deselects a node.
652      * @param {HTMLElement/Number/Record} node The node, node index or record to deselect
653      */
654     deselect : function(node){
655         if(this.isSelected(node)){
656             node = this.getNode(node);
657             this.selected.removeElement(node);
658             if(this.last == node.viewIndex){
659                 this.last = false;
660             }
661             Ext.fly(node).removeClass(this.selectedClass);
662             this.fireEvent("selectionchange", this, this.selected.elements);
663         }
664     },
665
666     <div id="method-Ext.DataView-select"></div>/**
667      * Selects a set of nodes.
668      * @param {Array/HTMLElement/String/Number/Ext.data.Record} nodeInfo An HTMLElement template node, index of a template node,
669      * id of a template node, record associated with a node or an array of any of those to select
670      * @param {Boolean} keepExisting (optional) true to keep existing selections
671      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
672      */
673     select : function(nodeInfo, keepExisting, suppressEvent){
674         if(Ext.isArray(nodeInfo)){
675             if(!keepExisting){
676                 this.clearSelections(true);
677             }
678             for(var i = 0, len = nodeInfo.length; i < len; i++){
679                 this.select(nodeInfo[i], true, true);
680             }
681             if(!suppressEvent){
682                 this.fireEvent("selectionchange", this, this.selected.elements);
683             }
684         } else{
685             var node = this.getNode(nodeInfo);
686             if(!keepExisting){
687                 this.clearSelections(true);
688             }
689             if(node && !this.isSelected(node)){
690                 if(this.fireEvent("beforeselect", this, node, this.selected.elements) !== false){
691                     Ext.fly(node).addClass(this.selectedClass);
692                     this.selected.add(node);
693                     this.last = node.viewIndex;
694                     if(!suppressEvent){
695                         this.fireEvent("selectionchange", this, this.selected.elements);
696                     }
697                 }
698             }
699         }
700     },
701
702     <div id="method-Ext.DataView-selectRange"></div>/**
703      * Selects a range of nodes. All nodes between start and end are selected.
704      * @param {Number} start The index of the first node in the range
705      * @param {Number} end The index of the last node in the range
706      * @param {Boolean} keepExisting (optional) True to retain existing selections
707      */
708     selectRange : function(start, end, keepExisting){
709         if(!keepExisting){
710             this.clearSelections(true);
711         }
712         this.select(this.getNodes(start, end), true);
713     },
714
715     <div id="method-Ext.DataView-getNode"></div>/**
716      * Gets a template node.
717      * @param {HTMLElement/String/Number/Ext.data.Record} nodeInfo An HTMLElement template node, index of a template node, 
718      * the id of a template node or the record associated with the node.
719      * @return {HTMLElement} The node or null if it wasn't found
720      */
721     getNode : function(nodeInfo){
722         if(Ext.isString(nodeInfo)){
723             return document.getElementById(nodeInfo);
724         }else if(Ext.isNumber(nodeInfo)){
725             return this.all.elements[nodeInfo];
726         }else if(nodeInfo instanceof Ext.data.Record){
727             var idx = this.store.indexOf(nodeInfo);
728             return this.all.elements[idx];
729         }
730         return nodeInfo;
731     },
732
733     <div id="method-Ext.DataView-getNodes"></div>/**
734      * Gets a range nodes.
735      * @param {Number} start (optional) The index of the first node in the range
736      * @param {Number} end (optional) The index of the last node in the range
737      * @return {Array} An array of nodes
738      */
739     getNodes : function(start, end){
740         var ns = this.all.elements,
741             nodes = [],
742             i;
743             
744         start = start || 0;
745         end = !Ext.isDefined(end) ? Math.max(ns.length - 1, 0) : end;
746         if(start <= end){
747             for(i = start; i <= end && ns[i]; i++){
748                 nodes.push(ns[i]);
749             }
750         } else{
751             for(i = start; i >= end && ns[i]; i--){
752                 nodes.push(ns[i]);
753             }
754         }
755         return nodes;
756     },
757
758     <div id="method-Ext.DataView-indexOf"></div>/**
759      * Finds the index of the passed node.
760      * @param {HTMLElement/String/Number/Record} nodeInfo An HTMLElement template node, index of a template node, the id of a template node
761      * or a record associated with a node.
762      * @return {Number} The index of the node or -1
763      */
764     indexOf : function(node){
765         node = this.getNode(node);
766         if(Ext.isNumber(node.viewIndex)){
767             return node.viewIndex;
768         }
769         return this.all.indexOf(node);
770     },
771
772     // private
773     onBeforeLoad : function(){
774         if(this.loadingText){
775             this.clearSelections(false, true);
776             this.getTemplateTarget().update('<div class="loading-indicator">'+this.loadingText+'</div>');
777             this.all.clear();
778         }
779     },
780
781     onDestroy : function(){
782         this.all.clear();
783         this.selected.clear();
784         Ext.DataView.superclass.onDestroy.call(this);
785         this.bindStore(null);
786     }
787 });
788
789 <div id="method-Ext.DataView-setStore"></div>/**
790  * Changes the data store bound to this view and refreshes it. (deprecated in favor of bindStore)
791  * @param {Store} store The store to bind to this view
792  */
793 Ext.DataView.prototype.setStore = Ext.DataView.prototype.bindStore;
794
795 Ext.reg('dataview', Ext.DataView);
796 </pre>    
797 </body>
798 </html>