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

« back to all changes in this revision

Viewing changes to gis/dhis-gis-geostat/mfbase/ext/source/legacy/View.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.0.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.View
 
11
 * @extends Ext.util.Observable
 
12
 * Create a "View" for an element based on a data model or Updater and the supplied DomHelper template.
 
13
 * This class also supports single and multi selection modes. <br>
 
14
 * Create a data model bound view:
 
15
 <pre><code>
 
16
 var store = new Ext.data.Store(...);
 
17
 
 
18
 var view = new Ext.View("my-element",
 
19
 '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
 
20
 {
 
21
 singleSelect: true,
 
22
 selectedClass: "xdataview-selected",
 
23
 store: store
 
24
 });
 
25
 
 
26
 // listen for node click?
 
27
 view.on("click", function(vw, index, node, e){
 
28
 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
 
29
 });
 
30
 
 
31
 // load XML data
 
32
 dataModel.load("foobar.xml");
 
33
 </code></pre>
 
34
 For an example of creating a JSON/Updater view, see {@link Ext.JsonView}.
 
35
 * <br><br>
 
36
 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
 
37
 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
 
38
 * @constructor
 
39
 * Create a new View
 
40
 * @param {Mixed} container The container element where the view is to be rendered.
 
41
 * @param {String/DomHelper.Template} tpl The rendering template or a string to create a template with
 
42
 * @param {Object} config The config object
 
43
 */
 
44
Ext.View = function(container, tpl, config){
 
45
    this.el = Ext.get(container);
 
46
    if(typeof tpl == "string"){
 
47
        tpl = new Ext.Template(tpl);
 
48
    }
 
49
    tpl.compile();
 
50
    /**
 
51
     * The template used by this View
 
52
     * @type {Ext.DomHelper.Template}
 
53
     */
 
54
    this.tpl = tpl;
 
55
 
 
56
    Ext.apply(this, config);
 
57
 
 
58
    /** @private */
 
59
    this.addEvents({
 
60
    /**
 
61
     * @event beforeclick
 
62
     * Fires before a click is processed. Returns false to cancel the default action.
 
63
     * @param {Ext.View} this
 
64
     * @param {Number} index The index of the target node
 
65
     * @param {HTMLElement} node The target node
 
66
     * @param {Ext.EventObject} e The raw event object
 
67
     */
 
68
        "beforeclick" : true,
 
69
    /**
 
70
     * @event click
 
71
     * Fires when a template node is clicked.
 
72
     * @param {Ext.View} this
 
73
     * @param {Number} index The index of the target node
 
74
     * @param {HTMLElement} node The target node
 
75
     * @param {Ext.EventObject} e The raw event object
 
76
     */
 
77
        "click" : true,
 
78
    /**
 
79
     * @event dblclick
 
80
     * Fires when a template node is double clicked.
 
81
     * @param {Ext.View} this
 
82
     * @param {Number} index The index of the target node
 
83
     * @param {HTMLElement} node The target node
 
84
     * @param {Ext.EventObject} e The raw event object
 
85
     */
 
86
        "dblclick" : true,
 
87
    /**
 
88
     * @event contextmenu
 
89
     * Fires when a template node is right clicked.
 
90
     * @param {Ext.View} this
 
91
     * @param {Number} index The index of the target node
 
92
     * @param {HTMLElement} node The target node
 
93
     * @param {Ext.EventObject} e The raw event object
 
94
     */
 
95
        "contextmenu" : true,
 
96
    /**
 
97
     * @event selectionchange
 
98
     * Fires when the selected nodes change.
 
99
     * @param {Ext.View} this
 
100
     * @param {Array} selections Array of the selected nodes
 
101
     */
 
102
        "selectionchange" : true,
 
103
 
 
104
    /**
 
105
     * @event beforeselect
 
106
     * Fires before a selection is made. If any handlers return false, the selection is cancelled.
 
107
     * @param {Ext.View} this
 
108
     * @param {HTMLElement} node The node to be selected
 
109
     * @param {Array} selections Array of currently selected nodes
 
110
     */
 
111
        "beforeselect" : true
 
112
    });
 
113
 
 
114
    this.el.on({
 
115
        "click": this.onClick,
 
116
        "dblclick": this.onDblClick,
 
117
        "contextmenu": this.onContextMenu,
 
118
        scope:this
 
119
    });
 
120
 
 
121
    this.selections = [];
 
122
    this.nodes = [];
 
123
    this.cmp = new Ext.CompositeElementLite([]);
 
124
    if(this.store){
 
125
        this.setStore(this.store, true);
 
126
    }
 
127
    Ext.View.superclass.constructor.call(this);
 
128
};
 
129
 
 
130
Ext.extend(Ext.View, Ext.util.Observable, {
 
131
    /**
 
132
     * The css class to add to selected nodes
 
133
     * @type {Ext.DomHelper.Template}
 
134
     */
 
135
    selectedClass : "x-view-selected",
 
136
    
 
137
    emptyText : "",
 
138
    /**
 
139
     * Returns the element this view is bound to.
 
140
     * @return {Ext.Element}
 
141
     */
 
142
    getEl : function(){
 
143
        return this.el;
 
144
    },
 
145
 
 
146
    /**
 
147
     * Refreshes the view.
 
148
     */
 
149
    refresh : function(){
 
150
        var t = this.tpl;
 
151
        this.clearSelections();
 
152
        this.el.update("");
 
153
        var html = [];
 
154
        var records = this.store.getRange();
 
155
        if(records.length < 1){
 
156
            this.el.update(this.emptyText);
 
157
            return;
 
158
        }
 
159
        for(var i = 0, len = records.length; i < len; i++){
 
160
            var data = this.prepareData(records[i].data, i, records[i]);
 
161
            html[html.length] = t.apply(data);
 
162
        }
 
163
        this.el.update(html.join(""));
 
164
        this.nodes = this.el.dom.childNodes;
 
165
        this.updateIndexes(0);
 
166
    },
 
167
 
 
168
    /**
 
169
     * Function to override to reformat the data that is sent to
 
170
     * the template for each node.
 
171
     * @param {Array/Object} data The raw data (array of colData for a data model bound view or
 
172
     * a JSON object for an Updater bound view).
 
173
     */
 
174
    prepareData : function(data){
 
175
        return data;
 
176
    },
 
177
 
 
178
    onUpdate : function(ds, record){
 
179
        this.clearSelections();
 
180
        var index = this.store.indexOf(record);
 
181
        var n = this.nodes[index];
 
182
        this.tpl.insertBefore(n, this.prepareData(record.data));
 
183
        n.parentNode.removeChild(n);
 
184
        this.updateIndexes(index, index);
 
185
    },
 
186
 
 
187
    onAdd : function(ds, records, index){
 
188
        this.clearSelections();
 
189
        if(this.nodes.length == 0){
 
190
            this.refresh();
 
191
            return;
 
192
        }
 
193
        var n = this.nodes[index];
 
194
        for(var i = 0, len = records.length; i < len; i++){
 
195
            var d = this.prepareData(records[i].data);
 
196
            if(n){
 
197
                this.tpl.insertBefore(n, d);
 
198
            }else{
 
199
                this.tpl.append(this.el, d);
 
200
            }
 
201
        }
 
202
        this.updateIndexes(index);
 
203
    },
 
204
 
 
205
    onRemove : function(ds, record, index){
 
206
        this.clearSelections();
 
207
        this.el.dom.removeChild(this.nodes[index]);
 
208
        this.updateIndexes(index);
 
209
    },
 
210
 
 
211
    /**
 
212
     * Refresh an individual node.
 
213
     * @param {Number} index
 
214
     */
 
215
    refreshNode : function(index){
 
216
        this.onUpdate(this.store, this.store.getAt(index));
 
217
    },
 
218
 
 
219
    updateIndexes : function(startIndex, endIndex){
 
220
        var ns = this.nodes;
 
221
        startIndex = startIndex || 0;
 
222
        endIndex = endIndex || ns.length - 1;
 
223
        for(var i = startIndex; i <= endIndex; i++){
 
224
            ns[i].nodeIndex = i;
 
225
        }
 
226
    },
 
227
 
 
228
    /**
 
229
     * Changes the data store this view uses and refresh the view.
 
230
     * @param {Store} store
 
231
     */
 
232
    setStore : function(store, initial){
 
233
        if(!initial && this.store){
 
234
            this.store.un("datachanged", this.refresh, this);
 
235
            this.store.un("add", this.onAdd, this);
 
236
            this.store.un("remove", this.onRemove, this);
 
237
            this.store.un("update", this.onUpdate, this);
 
238
            this.store.un("clear", this.refresh, this);
 
239
        }
 
240
        if(store){
 
241
            store.on("datachanged", this.refresh, this);
 
242
            store.on("add", this.onAdd, this);
 
243
            store.on("remove", this.onRemove, this);
 
244
            store.on("update", this.onUpdate, this);
 
245
            store.on("clear", this.refresh, this);
 
246
        }
 
247
        this.store = store;
 
248
        if(store){
 
249
            this.refresh();
 
250
        }
 
251
    },
 
252
 
 
253
    /**
 
254
     * Returns the template node the passed child belongs to or null if it doesn't belong to one.
 
255
     * @param {HTMLElement} node
 
256
     * @return {HTMLElement} The template node
 
257
     */
 
258
    findItemFromChild : function(node){
 
259
        var el = this.el.dom;
 
260
        if(!node || node.parentNode == el){
 
261
                    return node;
 
262
            }
 
263
            var p = node.parentNode;
 
264
            while(p && p != el){
 
265
            if(p.parentNode == el){
 
266
                return p;
 
267
            }
 
268
            p = p.parentNode;
 
269
        }
 
270
            return null;
 
271
    },
 
272
 
 
273
    /** @ignore */
 
274
    onClick : function(e){
 
275
        var item = this.findItemFromChild(e.getTarget());
 
276
        if(item){
 
277
            var index = this.indexOf(item);
 
278
            if(this.onItemClick(item, index, e) !== false){
 
279
                this.fireEvent("click", this, index, item, e);
 
280
            }
 
281
        }else{
 
282
            this.clearSelections();
 
283
        }
 
284
    },
 
285
 
 
286
    /** @ignore */
 
287
    onContextMenu : function(e){
 
288
        var item = this.findItemFromChild(e.getTarget());
 
289
        if(item){
 
290
            this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
 
291
        }
 
292
    },
 
293
 
 
294
    /** @ignore */
 
295
    onDblClick : function(e){
 
296
        var item = this.findItemFromChild(e.getTarget());
 
297
        if(item){
 
298
            this.fireEvent("dblclick", this, this.indexOf(item), item, e);
 
299
        }
 
300
    },
 
301
 
 
302
    onItemClick : function(item, index, e){
 
303
        if(this.fireEvent("beforeclick", this, index, item, e) === false){
 
304
            return false;
 
305
        }
 
306
        if(this.multiSelect || this.singleSelect){
 
307
            if(this.multiSelect && e.shiftKey && this.lastSelection){
 
308
                this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
 
309
            }else{
 
310
                this.select(item, this.multiSelect && e.ctrlKey);
 
311
                this.lastSelection = item;
 
312
            }
 
313
            e.preventDefault();
 
314
        }
 
315
        return true;
 
316
    },
 
317
 
 
318
    /**
 
319
     * Get the number of selected nodes.
 
320
     * @return {Number}
 
321
     */
 
322
    getSelectionCount : function(){
 
323
        return this.selections.length;
 
324
    },
 
325
 
 
326
    /**
 
327
     * Get the currently selected nodes.
 
328
     * @return {Array} An array of HTMLElements
 
329
     */
 
330
    getSelectedNodes : function(){
 
331
        return this.selections;
 
332
    },
 
333
 
 
334
    /**
 
335
     * Get the indexes of the selected nodes.
 
336
     * @return {Array}
 
337
     */
 
338
    getSelectedIndexes : function(){
 
339
        var indexes = [], s = this.selections;
 
340
        for(var i = 0, len = s.length; i < len; i++){
 
341
            indexes.push(s[i].nodeIndex);
 
342
        }
 
343
        return indexes;
 
344
    },
 
345
 
 
346
    /**
 
347
     * Clear all selections
 
348
     * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
 
349
     */
 
350
    clearSelections : function(suppressEvent){
 
351
        if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
 
352
            this.cmp.elements = this.selections;
 
353
            this.cmp.removeClass(this.selectedClass);
 
354
            this.selections = [];
 
355
            if(!suppressEvent){
 
356
                this.fireEvent("selectionchange", this, this.selections);
 
357
            }
 
358
        }
 
359
    },
 
360
 
 
361
    /**
 
362
     * Returns true if the passed node is selected
 
363
     * @param {HTMLElement/Number} node The node or node index
 
364
     * @return {Boolean}
 
365
     */
 
366
    isSelected : function(node){
 
367
        var s = this.selections;
 
368
        if(s.length < 1){
 
369
            return false;
 
370
        }
 
371
        node = this.getNode(node);
 
372
        return s.indexOf(node) !== -1;
 
373
    },
 
374
 
 
375
    /**
 
376
     * Selects nodes.
 
377
     * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
 
378
     * @param {Boolean} keepExisting (optional) true to keep existing selections
 
379
     * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
 
380
     */
 
381
    select : function(nodeInfo, keepExisting, suppressEvent){
 
382
        if(Ext.isArray(nodeInfo)){
 
383
            if(!keepExisting){
 
384
                this.clearSelections(true);
 
385
            }
 
386
            for(var i = 0, len = nodeInfo.length; i < len; i++){
 
387
                this.select(nodeInfo[i], true, true);
 
388
            }
 
389
        } else{
 
390
            var node = this.getNode(nodeInfo);
 
391
            if(node && !this.isSelected(node)){
 
392
                if(!keepExisting){
 
393
                    this.clearSelections(true);
 
394
                }
 
395
                if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
 
396
                    Ext.fly(node).addClass(this.selectedClass);
 
397
                    this.selections.push(node);
 
398
                    if(!suppressEvent){
 
399
                        this.fireEvent("selectionchange", this, this.selections);
 
400
                    }
 
401
                }
 
402
            }
 
403
        }
 
404
    },
 
405
 
 
406
    /**
 
407
     * Gets a template node.
 
408
     * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
 
409
     * @return {HTMLElement} The node or null if it wasn't found
 
410
     */
 
411
    getNode : function(nodeInfo){
 
412
        if(typeof nodeInfo == "string"){
 
413
            return document.getElementById(nodeInfo);
 
414
        }else if(typeof nodeInfo == "number"){
 
415
            return this.nodes[nodeInfo];
 
416
        }
 
417
        return nodeInfo;
 
418
    },
 
419
 
 
420
    /**
 
421
     * Gets a range template nodes.
 
422
     * @param {Number} startIndex
 
423
     * @param {Number} endIndex
 
424
     * @return {Array} An array of nodes
 
425
     */
 
426
    getNodes : function(start, end){
 
427
        var ns = this.nodes;
 
428
        start = start || 0;
 
429
        end = typeof end == "undefined" ? ns.length - 1 : end;
 
430
        var nodes = [];
 
431
        if(start <= end){
 
432
            for(var i = start; i <= end; i++){
 
433
                nodes.push(ns[i]);
 
434
            }
 
435
        } else{
 
436
            for(var i = start; i >= end; i--){
 
437
                nodes.push(ns[i]);
 
438
            }
 
439
        }
 
440
        return nodes;
 
441
    },
 
442
 
 
443
    /**
 
444
     * Finds the index of the passed node
 
445
     * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
 
446
     * @return {Number} The index of the node or -1
 
447
     */
 
448
    indexOf : function(node){
 
449
        node = this.getNode(node);
 
450
        if(typeof node.nodeIndex == "number"){
 
451
            return node.nodeIndex;
 
452
        }
 
453
        var ns = this.nodes;
 
454
        for(var i = 0, len = ns.length; i < len; i++){
 
455
            if(ns[i] == node){
 
456
                return i;
 
457
            }
 
458
        }
 
459
        return -1;
 
460
    }
 
461
});