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