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

« back to all changes in this revision

Viewing changes to gis/dhis-gis-geostat/mfbase/ext/source/widgets/menu/Menu.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.menu.Menu
 
11
 * @extends Ext.util.Observable
 
12
 * A menu object.  This is the container to which you add all other menu items.  Menu can also serve as a base class
 
13
 * when you want a specialized menu based off of another component (like {@link Ext.menu.DateMenu} for example).
 
14
 * @constructor
 
15
 * Creates a new Menu
 
16
 * @param {Object} config Configuration options
 
17
 */
 
18
Ext.menu.Menu = function(config){
 
19
    if(Ext.isArray(config)){
 
20
        config = {items:config};
 
21
    }
 
22
    Ext.apply(this, config);
 
23
    this.id = this.id || Ext.id();
 
24
    this.addEvents(
 
25
        /**
 
26
         * @event beforeshow
 
27
         * Fires before this menu is displayed
 
28
         * @param {Ext.menu.Menu} this
 
29
         */
 
30
        'beforeshow',
 
31
        /**
 
32
         * @event beforehide
 
33
         * Fires before this menu is hidden
 
34
         * @param {Ext.menu.Menu} this
 
35
         */
 
36
        'beforehide',
 
37
        /**
 
38
         * @event show
 
39
         * Fires after this menu is displayed
 
40
         * @param {Ext.menu.Menu} this
 
41
         */
 
42
        'show',
 
43
        /**
 
44
         * @event hide
 
45
         * Fires after this menu is hidden
 
46
         * @param {Ext.menu.Menu} this
 
47
         */
 
48
        'hide',
 
49
        /**
 
50
         * @event click
 
51
         * Fires when this menu is clicked (or when the enter key is pressed while it is active)
 
52
         * @param {Ext.menu.Menu} this
 
53
         * @param {Ext.menu.Item} menuItem The menu item that was clicked
 
54
         * @param {Ext.EventObject} e
 
55
         */
 
56
        'click',
 
57
        /**
 
58
         * @event mouseover
 
59
         * Fires when the mouse is hovering over this menu
 
60
         * @param {Ext.menu.Menu} this
 
61
         * @param {Ext.EventObject} e
 
62
         * @param {Ext.menu.Item} menuItem The menu item that was clicked
 
63
         */
 
64
        'mouseover',
 
65
        /**
 
66
         * @event mouseout
 
67
         * Fires when the mouse exits this menu
 
68
         * @param {Ext.menu.Menu} this
 
69
         * @param {Ext.EventObject} e
 
70
         * @param {Ext.menu.Item} menuItem The menu item that was clicked
 
71
         */
 
72
        'mouseout',
 
73
        /**
 
74
         * @event itemclick
 
75
         * Fires when a menu item contained in this menu is clicked
 
76
         * @param {Ext.menu.BaseItem} baseItem The BaseItem that was clicked
 
77
         * @param {Ext.EventObject} e
 
78
         */
 
79
        'itemclick'
 
80
    );
 
81
    Ext.menu.MenuMgr.register(this);
 
82
    Ext.menu.Menu.superclass.constructor.call(this);
 
83
    var mis = this.items;
 
84
    /**
 
85
     * A MixedCollection of this Menu's items
 
86
     * @property items
 
87
     * @type Ext.util.MixedCollection
 
88
     */
 
89
 
 
90
    this.items = new Ext.util.MixedCollection();
 
91
    if(mis){
 
92
        this.add.apply(this, mis);
 
93
    }
 
94
};
 
95
 
 
96
Ext.extend(Ext.menu.Menu, Ext.util.Observable, {
 
97
    /**
 
98
     * @cfg {Object} defaults
 
99
     * A config object that will be applied to all items added to this container either via the {@link #items}
 
100
     * config or via the {@link #add} method.  The defaults config can contain any number of
 
101
     * name/value property pairs to be added to each item, and should be valid for the types of items
 
102
     * being added to the menu.
 
103
     */
 
104
    /**
 
105
     * @cfg {Mixed} items
 
106
     * An array of items to be added to this menu.  See {@link #add} for a list of valid item types.
 
107
     */
 
108
    /**
 
109
     * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
 
110
     */
 
111
    minWidth : 120,
 
112
    /**
 
113
     * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
 
114
     * for bottom-right shadow (defaults to "sides")
 
115
     */
 
116
    shadow : "sides",
 
117
    /**
 
118
     * @cfg {String} subMenuAlign The {@link Ext.Element#alignTo} anchor position value to use for submenus of
 
119
     * this menu (defaults to "tl-tr?")
 
120
     */
 
121
    subMenuAlign : "tl-tr?",
 
122
    /**
 
123
     * @cfg {String} defaultAlign The default {@link Ext.Element#alignTo} anchor position value for this menu
 
124
     * relative to its element of origin (defaults to "tl-bl?")
 
125
     */
 
126
    defaultAlign : "tl-bl?",
 
127
    /**
 
128
     * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
 
129
     */
 
130
    allowOtherMenus : false,
 
131
    /**
 
132
     * @cfg {Boolean} ignoreParentClicks True to ignore clicks on any item in this menu that is a parent item (displays
 
133
     * a submenu) so that the submenu is not dismissed when clicking the parent item (defaults to false).
 
134
     */
 
135
    ignoreParentClicks : false,
 
136
 
 
137
    // private
 
138
    hidden:true,
 
139
 
 
140
    // private
 
141
    createEl : function(){
 
142
        return new Ext.Layer({
 
143
            cls: "x-menu",
 
144
            shadow:this.shadow,
 
145
            constrain: false,
 
146
            parentEl: this.parentEl || document.body,
 
147
            zindex:15000
 
148
        });
 
149
    },
 
150
 
 
151
    // private
 
152
    render : function(){
 
153
        if(this.el){
 
154
            return;
 
155
        }
 
156
        var el = this.el = this.createEl();
 
157
 
 
158
        if(!this.keyNav){
 
159
            this.keyNav = new Ext.menu.MenuNav(this);
 
160
        }
 
161
        if(this.plain){
 
162
            el.addClass("x-menu-plain");
 
163
        }
 
164
        if(this.cls){
 
165
            el.addClass(this.cls);
 
166
        }
 
167
        // generic focus element
 
168
        this.focusEl = el.createChild({
 
169
            tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
 
170
        });
 
171
        var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
 
172
        ul.on("click", this.onClick, this);
 
173
        ul.on("mouseover", this.onMouseOver, this);
 
174
        ul.on("mouseout", this.onMouseOut, this);
 
175
        this.items.each(function(item){
 
176
            var li = document.createElement("li");
 
177
            li.className = "x-menu-list-item";
 
178
            ul.dom.appendChild(li);
 
179
            item.render(li, this);
 
180
        }, this);
 
181
        this.ul = ul;
 
182
        this.autoWidth();
 
183
    },
 
184
 
 
185
    // private
 
186
    autoWidth : function(){
 
187
        var el = this.el, ul = this.ul;
 
188
        if(!el){
 
189
            return;
 
190
        }
 
191
        var w = this.width;
 
192
        if(w){
 
193
            el.setWidth(w);
 
194
        }else if(Ext.isIE){
 
195
            el.setWidth(this.minWidth);
 
196
            var t = el.dom.offsetWidth; // force recalc
 
197
            el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
 
198
        }
 
199
    },
 
200
 
 
201
    // private
 
202
    delayAutoWidth : function(){
 
203
        if(this.el){
 
204
            if(!this.awTask){
 
205
                this.awTask = new Ext.util.DelayedTask(this.autoWidth, this);
 
206
            }
 
207
            this.awTask.delay(20);
 
208
        }
 
209
    },
 
210
 
 
211
    // private
 
212
    findTargetItem : function(e){
 
213
        var t = e.getTarget(".x-menu-list-item", this.ul,  true);
 
214
        if(t && t.menuItemId){
 
215
            return this.items.get(t.menuItemId);
 
216
        }
 
217
    },
 
218
 
 
219
    // private
 
220
    onClick : function(e){
 
221
        var t;
 
222
        if(t = this.findTargetItem(e)){
 
223
            if(t.menu && this.ignoreParentClicks){
 
224
                t.expandMenu();
 
225
            }else{
 
226
                t.onClick(e);
 
227
                this.fireEvent("click", this, t, e);
 
228
            }
 
229
        }
 
230
    },
 
231
 
 
232
    // private
 
233
    setActiveItem : function(item, autoExpand){
 
234
        if(item != this.activeItem){
 
235
            if(this.activeItem){
 
236
                this.activeItem.deactivate();
 
237
            }
 
238
            this.activeItem = item;
 
239
            item.activate(autoExpand);
 
240
        }else if(autoExpand){
 
241
            item.expandMenu();
 
242
        }
 
243
    },
 
244
 
 
245
    // private
 
246
    tryActivate : function(start, step){
 
247
        var items = this.items;
 
248
        for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
 
249
            var item = items.get(i);
 
250
            if(!item.disabled && item.canActivate){
 
251
                this.setActiveItem(item, false);
 
252
                return item;
 
253
            }
 
254
        }
 
255
        return false;
 
256
    },
 
257
 
 
258
    // private
 
259
    onMouseOver : function(e){
 
260
        var t;
 
261
        if(t = this.findTargetItem(e)){
 
262
            if(t.canActivate && !t.disabled){
 
263
                this.setActiveItem(t, true);
 
264
            }
 
265
        }
 
266
        this.over = true;
 
267
        this.fireEvent("mouseover", this, e, t);
 
268
    },
 
269
 
 
270
    // private
 
271
    onMouseOut : function(e){
 
272
        var t;
 
273
        if(t = this.findTargetItem(e)){
 
274
            if(t == this.activeItem && t.shouldDeactivate(e)){
 
275
                this.activeItem.deactivate();
 
276
                delete this.activeItem;
 
277
            }
 
278
        }
 
279
        this.over = false;
 
280
        this.fireEvent("mouseout", this, e, t);
 
281
    },
 
282
 
 
283
    /**
 
284
     * Read-only.  Returns true if the menu is currently displayed, else false.
 
285
     * @type Boolean
 
286
     */
 
287
    isVisible : function(){
 
288
        return this.el && !this.hidden;
 
289
    },
 
290
 
 
291
    /**
 
292
     * Displays this menu relative to another element
 
293
     * @param {Mixed} element The element to align to
 
294
     * @param {String} position (optional) The {@link Ext.Element#alignTo} anchor position to use in aligning to
 
295
     * the element (defaults to this.defaultAlign)
 
296
     * @param {Ext.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
 
297
     */
 
298
    show : function(el, pos, parentMenu){
 
299
        this.parentMenu = parentMenu;
 
300
        if(!this.el){
 
301
            this.render();
 
302
        }
 
303
        this.fireEvent("beforeshow", this);
 
304
        this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
 
305
    },
 
306
 
 
307
    /**
 
308
     * Displays this menu at a specific xy position
 
309
     * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
 
310
     * @param {Ext.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
 
311
     */
 
312
    showAt : function(xy, parentMenu, /* private: */_e){
 
313
        this.parentMenu = parentMenu;
 
314
        if(!this.el){
 
315
            this.render();
 
316
        }
 
317
        if(_e !== false){
 
318
            this.fireEvent("beforeshow", this);
 
319
            xy = this.el.adjustForConstraints(xy);
 
320
        }
 
321
        this.el.setXY(xy);
 
322
        this.el.show();
 
323
        this.hidden = false;
 
324
        this.focus();
 
325
        this.fireEvent("show", this);
 
326
    },
 
327
 
 
328
    
 
329
 
 
330
    focus : function(){
 
331
        if(!this.hidden){
 
332
            this.doFocus.defer(50, this);
 
333
        }
 
334
    },
 
335
 
 
336
    doFocus : function(){
 
337
        if(!this.hidden){
 
338
            this.focusEl.focus();
 
339
        }
 
340
    },
 
341
 
 
342
    /**
 
343
     * Hides this menu and optionally all parent menus
 
344
     * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
 
345
     */
 
346
    hide : function(deep){
 
347
        if(this.el && this.isVisible()){
 
348
            this.fireEvent("beforehide", this);
 
349
            if(this.activeItem){
 
350
                this.activeItem.deactivate();
 
351
                this.activeItem = null;
 
352
            }
 
353
            this.el.hide();
 
354
            this.hidden = true;
 
355
            this.fireEvent("hide", this);
 
356
        }
 
357
        if(deep === true && this.parentMenu){
 
358
            this.parentMenu.hide(true);
 
359
        }
 
360
    },
 
361
 
 
362
    /**
 
363
     * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
 
364
     * Any of the following are valid:
 
365
     * <ul>
 
366
     * <li>Any menu item object based on {@link Ext.menu.BaseItem}</li>
 
367
     * <li>An HTMLElement object which will be converted to a menu item</li>
 
368
     * <li>A menu item config object that will be created as a new menu item</li>
 
369
     * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
 
370
     * it will be converted into a {@link Ext.menu.TextItem} and added</li>
 
371
     * </ul>
 
372
     * Usage:
 
373
     * <pre><code>
 
374
// Create the menu
 
375
var menu = new Ext.menu.Menu();
 
376
 
 
377
// Create a menu item to add by reference
 
378
var menuItem = new Ext.menu.Item({ text: 'New Item!' });
 
379
 
 
380
// Add a bunch of items at once using different methods.
 
381
// Only the last item added will be returned.
 
382
var item = menu.add(
 
383
    menuItem,                // add existing item by ref
 
384
    'Dynamic Item',          // new TextItem
 
385
    '-',                     // new separator
 
386
    { text: 'Config Item' }  // new item by config
 
387
);
 
388
</code></pre>
 
389
     * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
 
390
     * @return {Ext.menu.Item} The menu item that was added, or the last one if multiple items were added
 
391
     */
 
392
    add : function(){
 
393
        var a = arguments, l = a.length, item;
 
394
        for(var i = 0; i < l; i++){
 
395
            var el = a[i];
 
396
            if(el.render){ // some kind of Item
 
397
                item = this.addItem(el);
 
398
            }else if(typeof el == "string"){ // string
 
399
                if(el == "separator" || el == "-"){
 
400
                    item = this.addSeparator();
 
401
                }else{
 
402
                    item = this.addText(el);
 
403
                }
 
404
            }else if(el.tagName || el.el){ // element
 
405
                item = this.addElement(el);
 
406
            }else if(typeof el == "object"){ // must be menu item config?
 
407
                Ext.applyIf(el, this.defaults);
 
408
                item = this.addMenuItem(el);
 
409
            }
 
410
        }
 
411
        return item;
 
412
    },
 
413
 
 
414
    /**
 
415
     * Returns this menu's underlying {@link Ext.Element} object
 
416
     * @return {Ext.Element} The element
 
417
     */
 
418
    getEl : function(){
 
419
        if(!this.el){
 
420
            this.render();
 
421
        }
 
422
        return this.el;
 
423
    },
 
424
 
 
425
    /**
 
426
     * Adds a separator bar to the menu
 
427
     * @return {Ext.menu.Item} The menu item that was added
 
428
     */
 
429
    addSeparator : function(){
 
430
        return this.addItem(new Ext.menu.Separator());
 
431
    },
 
432
 
 
433
    /**
 
434
     * Adds an {@link Ext.Element} object to the menu
 
435
     * @param {Mixed} el The element or DOM node to add, or its id
 
436
     * @return {Ext.menu.Item} The menu item that was added
 
437
     */
 
438
    addElement : function(el){
 
439
        return this.addItem(new Ext.menu.BaseItem(el));
 
440
    },
 
441
 
 
442
    /**
 
443
     * Adds an existing object based on {@link Ext.menu.BaseItem} to the menu
 
444
     * @param {Ext.menu.Item} item The menu item to add
 
445
     * @return {Ext.menu.Item} The menu item that was added
 
446
     */
 
447
    addItem : function(item){
 
448
        this.items.add(item);
 
449
        if(this.ul){
 
450
            var li = document.createElement("li");
 
451
            li.className = "x-menu-list-item";
 
452
            this.ul.dom.appendChild(li);
 
453
            item.render(li, this);
 
454
            this.delayAutoWidth();
 
455
        }
 
456
        return item;
 
457
    },
 
458
 
 
459
    /**
 
460
     * Creates a new {@link Ext.menu.Item} based an the supplied config object and adds it to the menu
 
461
     * @param {Object} config A MenuItem config object
 
462
     * @return {Ext.menu.Item} The menu item that was added
 
463
     */
 
464
    addMenuItem : function(config){
 
465
        if(!(config instanceof Ext.menu.Item)){
 
466
            if(typeof config.checked == "boolean"){ // must be check menu item config?
 
467
                config = new Ext.menu.CheckItem(config);
 
468
            }else{
 
469
                config = new Ext.menu.Item(config);
 
470
            }
 
471
        }
 
472
        return this.addItem(config);
 
473
    },
 
474
 
 
475
    /**
 
476
     * Creates a new {@link Ext.menu.TextItem} with the supplied text and adds it to the menu
 
477
     * @param {String} text The text to display in the menu item
 
478
     * @return {Ext.menu.Item} The menu item that was added
 
479
     */
 
480
    addText : function(text){
 
481
        return this.addItem(new Ext.menu.TextItem(text));
 
482
    },
 
483
 
 
484
    /**
 
485
     * Inserts an existing object based on {@link Ext.menu.BaseItem} to the menu at a specified index
 
486
     * @param {Number} index The index in the menu's list of current items where the new item should be inserted
 
487
     * @param {Ext.menu.Item} item The menu item to add
 
488
     * @return {Ext.menu.Item} The menu item that was added
 
489
     */
 
490
    insert : function(index, item){
 
491
        this.items.insert(index, item);
 
492
        if(this.ul){
 
493
            var li = document.createElement("li");
 
494
            li.className = "x-menu-list-item";
 
495
            this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
 
496
            item.render(li, this);
 
497
            this.delayAutoWidth();
 
498
        }
 
499
        return item;
 
500
    },
 
501
 
 
502
    /**
 
503
     * Removes an {@link Ext.menu.Item} from the menu and destroys the object
 
504
     * @param {Ext.menu.Item} item The menu item to remove
 
505
     */
 
506
    remove : function(item){
 
507
        this.items.removeKey(item.id);
 
508
        item.destroy();
 
509
    },
 
510
 
 
511
    /**
 
512
     * Removes and destroys all items in the menu
 
513
     */
 
514
    removeAll : function(){
 
515
        if(this.items){
 
516
                var f;
 
517
                while(f = this.items.first()){
 
518
                    this.remove(f);
 
519
                }
 
520
        }
 
521
    },
 
522
 
 
523
    /**
 
524
     * Destroys the menu by  unregistering it from {@link Ext.menu.MenuMgr}, purging event listeners,
 
525
     * removing all of the menus items, then destroying the underlying {@link Ext.Element}
 
526
     */
 
527
    destroy : function(){
 
528
        this.beforeDestroy();
 
529
        Ext.menu.MenuMgr.unregister(this);
 
530
        if (this.keyNav) {
 
531
                this.keyNav.disable();  
 
532
        }
 
533
        this.removeAll();
 
534
        if (this.ul) {
 
535
                this.ul.removeAllListeners();   
 
536
        }
 
537
        if (this.el) {
 
538
                this.el.destroy();      
 
539
        }
 
540
    },
 
541
 
 
542
        // private
 
543
    beforeDestroy : Ext.emptyFn
 
544
 
 
545
});
 
546
 
 
547
// MenuNav is a private utility class used internally by the Menu
 
548
Ext.menu.MenuNav = function(menu){
 
549
    Ext.menu.MenuNav.superclass.constructor.call(this, menu.el);
 
550
    this.scope = this.menu = menu;
 
551
};
 
552
 
 
553
Ext.extend(Ext.menu.MenuNav, Ext.KeyNav, {
 
554
    doRelay : function(e, h){
 
555
        var k = e.getKey();
 
556
        if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
 
557
            this.menu.tryActivate(0, 1);
 
558
            return false;
 
559
        }
 
560
        return h.call(this.scope || this, e, this.menu);
 
561
    },
 
562
 
 
563
    up : function(e, m){
 
564
        if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
 
565
            m.tryActivate(m.items.length-1, -1);
 
566
        }
 
567
    },
 
568
 
 
569
    down : function(e, m){
 
570
        if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
 
571
            m.tryActivate(0, 1);
 
572
        }
 
573
    },
 
574
 
 
575
    right : function(e, m){
 
576
        if(m.activeItem){
 
577
            m.activeItem.expandMenu(true);
 
578
        }
 
579
    },
 
580
 
 
581
    left : function(e, m){
 
582
        m.hide();
 
583
        if(m.parentMenu && m.parentMenu.activeItem){
 
584
            m.parentMenu.activeItem.activate();
 
585
        }
 
586
    },
 
587
 
 
588
    enter : function(e, m){
 
589
        if(m.activeItem){
 
590
            e.stopPropagation();
 
591
            m.activeItem.onClick(e);
 
592
            m.fireEvent("click", this, m.activeItem);
 
593
            return true;
 
594
        }
 
595
    }
 
596
});
 
 
b'\\ No newline at end of file'