~mortenoh/+junk/dhis2-detailed-import-export

« back to all changes in this revision

Viewing changes to gis/dhis-gis-geostat/mfbase/ext/source/widgets/DataView.js

  • Committer: larshelge at gmail
  • Date: 2009-03-03 16:46:36 UTC
  • Revision ID: larshelge@gmail.com-20090303164636-2sjlrquo7ib1gf7r
Initial check-in

Show diffs side-by-side

added added

removed removed

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