Bienvenue sur PostGIS.fr

Bienvenue sur PostGIS.fr , le site de la communauté des utilisateurs francophones de PostGIS.

PostGIS ajoute le support d'objets géographique à la base de données PostgreSQL. En effet, PostGIS "spatialise" le serverur PostgreSQL, ce qui permet de l'utiliser comme une base de données SIG.

Maintenu à jour, en fonction de nos disponibilités et des diverses sorties des outils que nous testons, nous vous proposons l'ensemble de nos travaux publiés en langue française.

source: trunk/workshop-routing-foss4g/web/ext/pkgs/pkg-menu-debug.js @ 76

Revision 76, 55.3 KB checked in by djay, 12 years ago (diff)

Ajout du répertoire web

  • Property svn:executable set to *
Line 
1/*!
2 * Ext JS Library 3.4.0
3 * Copyright(c) 2006-2011 Sencha Inc.
4 * licensing@sencha.com
5 * http://www.sencha.com/license
6 */
7/**
8 * @class Ext.menu.Menu
9 * @extends Ext.Container
10 * <p>A menu object.  This is the container to which you may add menu items.  Menu can also serve as a base class
11 * when you want a specialized menu based off of another component (like {@link Ext.menu.DateMenu} for example).</p>
12 * <p>Menus may contain either {@link Ext.menu.Item menu items}, or general {@link Ext.Component Component}s.</p>
13 * <p>To make a contained general {@link Ext.Component Component} line up with other {@link Ext.menu.Item menu items}
14 * specify <tt>iconCls: 'no-icon'</tt>.  This reserves a space for an icon, and indents the Component in line
15 * with the other menu items.  See {@link Ext.form.ComboBox}.{@link Ext.form.ComboBox#getListParent getListParent}
16 * for an example.</p>
17 * <p>By default, Menus are absolutely positioned, floating Components. By configuring a Menu with
18 * <b><tt>{@link #floating}:false</tt></b>, a Menu may be used as child of a Container.</p>
19 *
20 * @xtype menu
21 */
22Ext.menu.Menu = Ext.extend(Ext.Container, {
23    /**
24     * @cfg {Object} defaults
25     * A config object that will be applied to all items added to this container either via the {@link #items}
26     * config or via the {@link #add} method.  The defaults config can contain any number of
27     * name/value property pairs to be added to each item, and should be valid for the types of items
28     * being added to the menu.
29     */
30    /**
31     * @cfg {Mixed} items
32     * An array of items to be added to this menu. Menus may contain either {@link Ext.menu.Item menu items},
33     * or general {@link Ext.Component Component}s.
34     */
35    /**
36     * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37     */
38    minWidth : 120,
39    /**
40     * @cfg {Boolean/String} shadow True or 'sides' for the default effect, 'frame' for 4-way shadow, and 'drop'
41     * for bottom-right shadow (defaults to 'sides')
42     */
43    shadow : 'sides',
44    /**
45     * @cfg {String} subMenuAlign The {@link Ext.Element#alignTo} anchor position value to use for submenus of
46     * this menu (defaults to 'tl-tr?')
47     */
48    subMenuAlign : 'tl-tr?',
49    /**
50     * @cfg {String} defaultAlign The default {@link Ext.Element#alignTo} anchor position value for this menu
51     * relative to its element of origin (defaults to 'tl-bl?')
52     */
53    defaultAlign : 'tl-bl?',
54    /**
55     * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
56     */
57    allowOtherMenus : false,
58    /**
59     * @cfg {Boolean} ignoreParentClicks True to ignore clicks on any item in this menu that is a parent item (displays
60     * a submenu) so that the submenu is not dismissed when clicking the parent item (defaults to false).
61     */
62    ignoreParentClicks : false,
63    /**
64     * @cfg {Boolean} enableScrolling True to allow the menu container to have scroller controls if the menu is too long (defaults to true).
65     */
66    enableScrolling : true,
67    /**
68     * @cfg {Number} maxHeight The maximum height of the menu. Only applies when enableScrolling is set to True (defaults to null).
69     */
70    maxHeight : null,
71    /**
72     * @cfg {Number} scrollIncrement The amount to scroll the menu. Only applies when enableScrolling is set to True (defaults to 24).
73     */
74    scrollIncrement : 24,
75    /**
76     * @cfg {Boolean} showSeparator True to show the icon separator. (defaults to true).
77     */
78    showSeparator : true,
79    /**
80     * @cfg {Array} defaultOffsets An array specifying the [x, y] offset in pixels by which to
81     * change the default Menu popup position after aligning according to the {@link #defaultAlign}
82     * configuration. Defaults to <tt>[0, 0]</tt>.
83     */
84    defaultOffsets : [0, 0],
85
86    /**
87     * @cfg {Boolean} plain
88     * True to remove the incised line down the left side of the menu. Defaults to <tt>false</tt>.
89     */
90    plain : false,
91
92    /**
93     * @cfg {Boolean} floating
94     * <p>By default, a Menu configured as <b><code>floating:true</code></b>
95     * will be rendered as an {@link Ext.Layer} (an absolutely positioned,
96     * floating Component with zindex=15000).
97     * If configured as <b><code>floating:false</code></b>, the Menu may be
98     * used as child item of another Container instead of a free-floating
99     * {@link Ext.Layer Layer}.
100     */
101    floating : true,
102
103
104    /**
105     * @cfg {Number} zIndex
106     * zIndex to use when the menu is floating.
107     */
108    zIndex: 15000,
109
110    // private
111    hidden : true,
112
113    /**
114     * @cfg {String/Object} layout
115     * This class assigns a default layout (<code>layout:'<b>menu</b>'</code>).
116     * Developers <i>may</i> override this configuration option if another layout is required.
117     * See {@link Ext.Container#layout} for additional information.
118     */
119    layout : 'menu',
120    hideMode : 'offsets',    // Important for laying out Components
121    scrollerHeight : 8,
122    autoLayout : true,       // Provided for backwards compat
123    defaultType : 'menuitem',
124    bufferResize : false,
125
126    initComponent : function(){
127        if(Ext.isArray(this.initialConfig)){
128            Ext.apply(this, {items:this.initialConfig});
129        }
130        this.addEvents(
131            /**
132             * @event click
133             * Fires when this menu is clicked (or when the enter key is pressed while it is active)
134             * @param {Ext.menu.Menu} this
135            * @param {Ext.menu.Item} menuItem The menu item that was clicked
136             * @param {Ext.EventObject} e
137             */
138            'click',
139            /**
140             * @event mouseover
141             * Fires when the mouse is hovering over this menu
142             * @param {Ext.menu.Menu} this
143             * @param {Ext.EventObject} e
144             * @param {Ext.menu.Item} menuItem The menu item that was clicked
145             */
146            'mouseover',
147            /**
148             * @event mouseout
149             * Fires when the mouse exits this menu
150             * @param {Ext.menu.Menu} this
151             * @param {Ext.EventObject} e
152             * @param {Ext.menu.Item} menuItem The menu item that was clicked
153             */
154            'mouseout',
155            /**
156             * @event itemclick
157             * Fires when a menu item contained in this menu is clicked
158             * @param {Ext.menu.BaseItem} baseItem The BaseItem that was clicked
159             * @param {Ext.EventObject} e
160             */
161            'itemclick'
162        );
163        Ext.menu.MenuMgr.register(this);
164        if(this.floating){
165            Ext.EventManager.onWindowResize(this.hide, this);
166        }else{
167            if(this.initialConfig.hidden !== false){
168                this.hidden = false;
169            }
170            this.internalDefaults = {hideOnClick: false};
171        }
172        Ext.menu.Menu.superclass.initComponent.call(this);
173        if(this.autoLayout){
174            var fn = this.doLayout.createDelegate(this, []);
175            this.on({
176                add: fn,
177                remove: fn
178            });
179        }
180    },
181
182    //private
183    getLayoutTarget : function() {
184        return this.ul;
185    },
186
187    // private
188    onRender : function(ct, position){
189        if(!ct){
190            ct = Ext.getBody();
191        }
192
193        var dh = {
194            id: this.getId(),
195            cls: 'x-menu ' + ((this.floating) ? 'x-menu-floating x-layer ' : '') + (this.cls || '') + (this.plain ? ' x-menu-plain' : '') + (this.showSeparator ? '' : ' x-menu-nosep'),
196            style: this.style,
197            cn: [
198                {tag: 'a', cls: 'x-menu-focus', href: '#', onclick: 'return false;', tabIndex: '-1'},
199                {tag: 'ul', cls: 'x-menu-list'}
200            ]
201        };
202        if(this.floating){
203            this.el = new Ext.Layer({
204                shadow: this.shadow,
205                dh: dh,
206                constrain: false,
207                parentEl: ct,
208                zindex: this.zIndex
209            });
210        }else{
211            this.el = ct.createChild(dh);
212        }
213        Ext.menu.Menu.superclass.onRender.call(this, ct, position);
214
215        if(!this.keyNav){
216            this.keyNav = new Ext.menu.MenuNav(this);
217        }
218        // generic focus element
219        this.focusEl = this.el.child('a.x-menu-focus');
220        this.ul = this.el.child('ul.x-menu-list');
221        this.mon(this.ul, {
222            scope: this,
223            click: this.onClick,
224            mouseover: this.onMouseOver,
225            mouseout: this.onMouseOut
226        });
227        if(this.enableScrolling){
228            this.mon(this.el, {
229                scope: this,
230                delegate: '.x-menu-scroller',
231                click: this.onScroll,
232                mouseover: this.deactivateActive
233            });
234        }
235    },
236
237    // private
238    findTargetItem : function(e){
239        var t = e.getTarget('.x-menu-list-item', this.ul, true);
240        if(t && t.menuItemId){
241            return this.items.get(t.menuItemId);
242        }
243    },
244
245    // private
246    onClick : function(e){
247        var t = this.findTargetItem(e);
248        if(t){
249            if(t.isFormField){
250                this.setActiveItem(t);
251            }else if(t instanceof Ext.menu.BaseItem){
252                if(t.menu && this.ignoreParentClicks){
253                    t.expandMenu();
254                    e.preventDefault();
255                }else if(t.onClick){
256                    t.onClick(e);
257                    this.fireEvent('click', this, t, e);
258                }
259            }
260        }
261    },
262
263    // private
264    setActiveItem : function(item, autoExpand){
265        if(item != this.activeItem){
266            this.deactivateActive();
267            if((this.activeItem = item).isFormField){
268                item.focus();
269            }else{
270                item.activate(autoExpand);
271            }
272        }else if(autoExpand){
273            item.expandMenu();
274        }
275    },
276
277    deactivateActive : function(){
278        var a = this.activeItem;
279        if(a){
280            if(a.isFormField){
281                //Fields cannot deactivate, but Combos must collapse
282                if(a.collapse){
283                    a.collapse();
284                }
285            }else{
286                a.deactivate();
287            }
288            delete this.activeItem;
289        }
290    },
291
292    // private
293    tryActivate : function(start, step){
294        var items = this.items;
295        for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
296            var item = items.get(i);
297            if(item.isVisible() && !item.disabled && (item.canActivate || item.isFormField)){
298                this.setActiveItem(item, false);
299                return item;
300            }
301        }
302        return false;
303    },
304
305    // private
306    onMouseOver : function(e){
307        var t = this.findTargetItem(e);
308        if(t){
309            if(t.canActivate && !t.disabled){
310                this.setActiveItem(t, true);
311            }
312        }
313        this.over = true;
314        this.fireEvent('mouseover', this, e, t);
315    },
316
317    // private
318    onMouseOut : function(e){
319        var t = this.findTargetItem(e);
320        if(t){
321            if(t == this.activeItem && t.shouldDeactivate && t.shouldDeactivate(e)){
322                this.activeItem.deactivate();
323                delete this.activeItem;
324            }
325        }
326        this.over = false;
327        this.fireEvent('mouseout', this, e, t);
328    },
329
330    // private
331    onScroll : function(e, t){
332        if(e){
333            e.stopEvent();
334        }
335        var ul = this.ul.dom, top = Ext.fly(t).is('.x-menu-scroller-top');
336        ul.scrollTop += this.scrollIncrement * (top ? -1 : 1);
337        if(top ? ul.scrollTop <= 0 : ul.scrollTop + this.activeMax >= ul.scrollHeight){
338           this.onScrollerOut(null, t);
339        }
340    },
341
342    // private
343    onScrollerIn : function(e, t){
344        var ul = this.ul.dom, top = Ext.fly(t).is('.x-menu-scroller-top');
345        if(top ? ul.scrollTop > 0 : ul.scrollTop + this.activeMax < ul.scrollHeight){
346            Ext.fly(t).addClass(['x-menu-item-active', 'x-menu-scroller-active']);
347        }
348    },
349
350    // private
351    onScrollerOut : function(e, t){
352        Ext.fly(t).removeClass(['x-menu-item-active', 'x-menu-scroller-active']);
353    },
354
355    /**
356     * If <code>{@link #floating}=true</code>, shows this menu relative to
357     * another element using {@link #showat}, otherwise uses {@link Ext.Component#show}.
358     * @param {Mixed} element The element to align to
359     * @param {String} position (optional) The {@link Ext.Element#alignTo} anchor position to use in aligning to
360     * the element (defaults to this.defaultAlign)
361     * @param {Ext.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
362     */
363    show : function(el, pos, parentMenu){
364        if(this.floating){
365            this.parentMenu = parentMenu;
366            if(!this.el){
367                this.render();
368                this.doLayout(false, true);
369            }
370            this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign, this.defaultOffsets), parentMenu);
371        }else{
372            Ext.menu.Menu.superclass.show.call(this);
373        }
374    },
375
376    /**
377     * Displays this menu at a specific xy position and fires the 'show' event if a
378     * handler for the 'beforeshow' event does not return false cancelling the operation.
379     * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
380     * @param {Ext.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
381     */
382    showAt : function(xy, parentMenu){
383        if(this.fireEvent('beforeshow', this) !== false){
384            this.parentMenu = parentMenu;
385            if(!this.el){
386                this.render();
387            }
388            if(this.enableScrolling){
389                // set the position so we can figure out the constrain value.
390                this.el.setXY(xy);
391                //constrain the value, keep the y coordinate the same
392                xy[1] = this.constrainScroll(xy[1]);
393                xy = [this.el.adjustForConstraints(xy)[0], xy[1]];
394            }else{
395                //constrain to the viewport.
396                xy = this.el.adjustForConstraints(xy);
397            }
398            this.el.setXY(xy);
399            this.el.show();
400            Ext.menu.Menu.superclass.onShow.call(this);
401            if(Ext.isIE){
402                // internal event, used so we don't couple the layout to the menu
403                this.fireEvent('autosize', this);
404                if(!Ext.isIE8){
405                    this.el.repaint();
406                }
407            }
408            this.hidden = false;
409            this.focus();
410            this.fireEvent('show', this);
411        }
412    },
413
414    constrainScroll : function(y){
415        var max, full = this.ul.setHeight('auto').getHeight(),
416            returnY = y, normalY, parentEl, scrollTop, viewHeight;
417        if(this.floating){
418            parentEl = Ext.fly(this.el.dom.parentNode);
419            scrollTop = parentEl.getScroll().top;
420            viewHeight = parentEl.getViewSize().height;
421            //Normalize y by the scroll position for the parent element.  Need to move it into the coordinate space
422            //of the view.
423            normalY = y - scrollTop;
424            max = this.maxHeight ? this.maxHeight : viewHeight - normalY;
425            if(full > viewHeight) {
426                max = viewHeight;
427                //Set returnY equal to (0,0) in view space by reducing y by the value of normalY
428                returnY = y - normalY;
429            } else if(max < full) {
430                returnY = y - (full - max);
431                max = full;
432            }
433        }else{
434            max = this.getHeight();
435        }
436        // Always respect maxHeight
437        if (this.maxHeight){
438            max = Math.min(this.maxHeight, max);
439        }
440        if(full > max && max > 0){
441            this.activeMax = max - this.scrollerHeight * 2 - this.el.getFrameWidth('tb') - Ext.num(this.el.shadowOffset, 0);
442            this.ul.setHeight(this.activeMax);
443            this.createScrollers();
444            this.el.select('.x-menu-scroller').setDisplayed('');
445        }else{
446            this.ul.setHeight(full);
447            this.el.select('.x-menu-scroller').setDisplayed('none');
448        }
449        this.ul.dom.scrollTop = 0;
450        return returnY;
451    },
452
453    createScrollers : function(){
454        if(!this.scroller){
455            this.scroller = {
456                pos: 0,
457                top: this.el.insertFirst({
458                    tag: 'div',
459                    cls: 'x-menu-scroller x-menu-scroller-top',
460                    html: '&#160;'
461                }),
462                bottom: this.el.createChild({
463                    tag: 'div',
464                    cls: 'x-menu-scroller x-menu-scroller-bottom',
465                    html: '&#160;'
466                })
467            };
468            this.scroller.top.hover(this.onScrollerIn, this.onScrollerOut, this);
469            this.scroller.topRepeater = new Ext.util.ClickRepeater(this.scroller.top, {
470                listeners: {
471                    click: this.onScroll.createDelegate(this, [null, this.scroller.top], false)
472                }
473            });
474            this.scroller.bottom.hover(this.onScrollerIn, this.onScrollerOut, this);
475            this.scroller.bottomRepeater = new Ext.util.ClickRepeater(this.scroller.bottom, {
476                listeners: {
477                    click: this.onScroll.createDelegate(this, [null, this.scroller.bottom], false)
478                }
479            });
480        }
481    },
482
483    onLayout : function(){
484        if(this.isVisible()){
485            if(this.enableScrolling){
486                this.constrainScroll(this.el.getTop());
487            }
488            if(this.floating){
489                this.el.sync();
490            }
491        }
492    },
493
494    focus : function(){
495        if(!this.hidden){
496            this.doFocus.defer(50, this);
497        }
498    },
499
500    doFocus : function(){
501        if(!this.hidden){
502            this.focusEl.focus();
503        }
504    },
505
506    /**
507     * Hides this menu and optionally all parent menus
508     * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
509     */
510    hide : function(deep){
511        if (!this.isDestroyed) {
512            this.deepHide = deep;
513            Ext.menu.Menu.superclass.hide.call(this);
514            delete this.deepHide;
515        }
516    },
517
518    // private
519    onHide : function(){
520        Ext.menu.Menu.superclass.onHide.call(this);
521        this.deactivateActive();
522        if(this.el && this.floating){
523            this.el.hide();
524        }
525        var pm = this.parentMenu;
526        if(this.deepHide === true && pm){
527            if(pm.floating){
528                pm.hide(true);
529            }else{
530                pm.deactivateActive();
531            }
532        }
533    },
534
535    // private
536    lookupComponent : function(c){
537         if(Ext.isString(c)){
538            c = (c == 'separator' || c == '-') ? new Ext.menu.Separator() : new Ext.menu.TextItem(c);
539             this.applyDefaults(c);
540         }else{
541            if(Ext.isObject(c)){
542                c = this.getMenuItem(c);
543            }else if(c.tagName || c.el){ // element. Wrap it.
544                c = new Ext.BoxComponent({
545                    el: c
546                });
547            }
548         }
549         return c;
550    },
551
552    applyDefaults : function(c) {
553        if (!Ext.isString(c)) {
554            c = Ext.menu.Menu.superclass.applyDefaults.call(this, c);
555            var d = this.internalDefaults;
556            if(d){
557                if(c.events){
558                    Ext.applyIf(c.initialConfig, d);
559                    Ext.apply(c, d);
560                }else{
561                    Ext.applyIf(c, d);
562                }
563            }
564        }
565        return c;
566    },
567
568    // private
569    getMenuItem : function(config) {
570        config.ownerCt = this;
571       
572        if (!config.isXType) {
573            if (!config.xtype && Ext.isBoolean(config.checked)) {
574                return new Ext.menu.CheckItem(config);
575            }
576            return Ext.create(config, this.defaultType);
577        }
578        return config;
579    },
580
581    /**
582     * Adds a separator bar to the menu
583     * @return {Ext.menu.Item} The menu item that was added
584     */
585    addSeparator : function() {
586        return this.add(new Ext.menu.Separator());
587    },
588
589    /**
590     * Adds an {@link Ext.Element} object to the menu
591     * @param {Mixed} el The element or DOM node to add, or its id
592     * @return {Ext.menu.Item} The menu item that was added
593     */
594    addElement : function(el) {
595        return this.add(new Ext.menu.BaseItem({
596            el: el
597        }));
598    },
599
600    /**
601     * Adds an existing object based on {@link Ext.menu.BaseItem} to the menu
602     * @param {Ext.menu.Item} item The menu item to add
603     * @return {Ext.menu.Item} The menu item that was added
604     */
605    addItem : function(item) {
606        return this.add(item);
607    },
608
609    /**
610     * Creates a new {@link Ext.menu.Item} based an the supplied config object and adds it to the menu
611     * @param {Object} config A MenuItem config object
612     * @return {Ext.menu.Item} The menu item that was added
613     */
614    addMenuItem : function(config) {
615        return this.add(this.getMenuItem(config));
616    },
617
618    /**
619     * Creates a new {@link Ext.menu.TextItem} with the supplied text and adds it to the menu
620     * @param {String} text The text to display in the menu item
621     * @return {Ext.menu.Item} The menu item that was added
622     */
623    addText : function(text){
624        return this.add(new Ext.menu.TextItem(text));
625    },
626
627    //private
628    onDestroy : function(){
629        Ext.EventManager.removeResizeListener(this.hide, this);
630        var pm = this.parentMenu;
631        if(pm && pm.activeChild == this){
632            delete pm.activeChild;
633        }
634        delete this.parentMenu;
635        Ext.menu.Menu.superclass.onDestroy.call(this);
636        Ext.menu.MenuMgr.unregister(this);
637        if(this.keyNav) {
638            this.keyNav.disable();
639        }
640        var s = this.scroller;
641        if(s){
642            Ext.destroy(s.topRepeater, s.bottomRepeater, s.top, s.bottom);
643        }
644        Ext.destroy(
645            this.el,
646            this.focusEl,
647            this.ul
648        );
649    }
650});
651
652Ext.reg('menu', Ext.menu.Menu);
653
654// MenuNav is a private utility class used internally by the Menu
655Ext.menu.MenuNav = Ext.extend(Ext.KeyNav, function(){
656    function up(e, m){
657        if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
658            m.tryActivate(m.items.length-1, -1);
659        }
660    }
661    function down(e, m){
662        if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
663            m.tryActivate(0, 1);
664        }
665    }
666    return {
667        constructor : function(menu){
668            Ext.menu.MenuNav.superclass.constructor.call(this, menu.el);
669            this.scope = this.menu = menu;
670        },
671
672        doRelay : function(e, h){
673            var k = e.getKey();
674//          Keystrokes within a form Field (e.g.: down in a Combo) do not navigate. Allow only TAB
675            if (this.menu.activeItem && this.menu.activeItem.isFormField && k != e.TAB) {
676                return false;
677            }
678            if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
679                this.menu.tryActivate(0, 1);
680                return false;
681            }
682            return h.call(this.scope || this, e, this.menu);
683        },
684
685        tab: function(e, m) {
686            e.stopEvent();
687            if (e.shiftKey) {
688                up(e, m);
689            } else {
690                down(e, m);
691            }
692        },
693
694        up : up,
695
696        down : down,
697
698        right : function(e, m){
699            if(m.activeItem){
700                m.activeItem.expandMenu(true);
701            }
702        },
703
704        left : function(e, m){
705            m.hide();
706            if(m.parentMenu && m.parentMenu.activeItem){
707                m.parentMenu.activeItem.activate();
708            }
709        },
710
711        enter : function(e, m){
712            if(m.activeItem){
713                e.stopPropagation();
714                m.activeItem.onClick(e);
715                m.fireEvent('click', this, m.activeItem);
716                return true;
717            }
718        }
719    };
720}());
721/**
722 * @class Ext.menu.MenuMgr
723 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
724 * @singleton
725 */
726Ext.menu.MenuMgr = function(){
727   var menus, 
728       active, 
729       map,
730       groups = {}, 
731       attached = false, 
732       lastShow = new Date();
733   
734
735   // private - called when first menu is created
736   function init(){
737       menus = {};
738       active = new Ext.util.MixedCollection();
739       map = Ext.getDoc().addKeyListener(27, hideAll);
740       map.disable();
741   }
742
743   // private
744   function hideAll(){
745       if(active && active.length > 0){
746           var c = active.clone();
747           c.each(function(m){
748               m.hide();
749           });
750           return true;
751       }
752       return false;
753   }
754
755   // private
756   function onHide(m){
757       active.remove(m);
758       if(active.length < 1){
759           map.disable();
760           Ext.getDoc().un("mousedown", onMouseDown);
761           attached = false;
762       }
763   }
764
765   // private
766   function onShow(m){
767       var last = active.last();
768       lastShow = new Date();
769       active.add(m);
770       if(!attached){
771           map.enable();
772           Ext.getDoc().on("mousedown", onMouseDown);
773           attached = true;
774       }
775       if(m.parentMenu){
776          m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
777          m.parentMenu.activeChild = m;
778       }else if(last && !last.isDestroyed && last.isVisible()){
779          m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
780       }
781   }
782
783   // private
784   function onBeforeHide(m){
785       if(m.activeChild){
786           m.activeChild.hide();
787       }
788       if(m.autoHideTimer){
789           clearTimeout(m.autoHideTimer);
790           delete m.autoHideTimer;
791       }
792   }
793
794   // private
795   function onBeforeShow(m){
796       var pm = m.parentMenu;
797       if(!pm && !m.allowOtherMenus){
798           hideAll();
799       }else if(pm && pm.activeChild){
800           pm.activeChild.hide();
801       }
802   }
803
804   // private
805   function onMouseDown(e){
806       if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
807           hideAll();
808       }
809   }
810
811   return {
812
813       /**
814        * Hides all menus that are currently visible
815        * @return {Boolean} success True if any active menus were hidden.
816        */
817       hideAll : function(){
818            return hideAll();
819       },
820
821       // private
822       register : function(menu){
823           if(!menus){
824               init();
825           }
826           menus[menu.id] = menu;
827           menu.on({
828               beforehide: onBeforeHide,
829               hide: onHide,
830               beforeshow: onBeforeShow,
831               show: onShow
832           });
833       },
834
835        /**
836         * Returns a {@link Ext.menu.Menu} object
837         * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
838         * be used to generate and return a new Menu instance.
839         * @return {Ext.menu.Menu} The specified menu, or null if none are found
840         */
841       get : function(menu){
842           if(typeof menu == "string"){ // menu id
843               if(!menus){  // not initialized, no menus to return
844                   return null;
845               }
846               return menus[menu];
847           }else if(menu.events){  // menu instance
848               return menu;
849           }else if(typeof menu.length == 'number'){ // array of menu items?
850               return new Ext.menu.Menu({items:menu});
851           }else{ // otherwise, must be a config
852               return Ext.create(menu, 'menu');
853           }
854       },
855
856       // private
857       unregister : function(menu){
858           delete menus[menu.id];
859           menu.un("beforehide", onBeforeHide);
860           menu.un("hide", onHide);
861           menu.un("beforeshow", onBeforeShow);
862           menu.un("show", onShow);
863       },
864
865       // private
866       registerCheckable : function(menuItem){
867           var g = menuItem.group;
868           if(g){
869               if(!groups[g]){
870                   groups[g] = [];
871               }
872               groups[g].push(menuItem);
873           }
874       },
875
876       // private
877       unregisterCheckable : function(menuItem){
878           var g = menuItem.group;
879           if(g){
880               groups[g].remove(menuItem);
881           }
882       },
883       
884       // private
885       onCheckChange: function(item, state){
886           if(item.group && state){
887               var group = groups[item.group],
888                   i = 0,
889                   len = group.length,
890                   current;
891                   
892               for(; i < len; i++){
893                   current = group[i];
894                   if(current != item){
895                       current.setChecked(false);
896                   }
897               }
898           }
899       },
900
901       getCheckedItem : function(groupId){
902           var g = groups[groupId];
903           if(g){
904               for(var i = 0, l = g.length; i < l; i++){
905                   if(g[i].checked){
906                       return g[i];
907                   }
908               }
909           }
910           return null;
911       },
912
913       setCheckedItem : function(groupId, itemId){
914           var g = groups[groupId];
915           if(g){
916               for(var i = 0, l = g.length; i < l; i++){
917                   if(g[i].id == itemId){
918                       g[i].setChecked(true);
919                   }
920               }
921           }
922           return null;
923       }
924   };
925}();
926/**
927 * @class Ext.menu.BaseItem
928 * @extends Ext.Component
929 * The base class for all items that render into menus.  BaseItem provides default rendering, activated state
930 * management and base configuration options shared by all menu components.
931 * @constructor
932 * Creates a new BaseItem
933 * @param {Object} config Configuration options
934 * @xtype menubaseitem
935 */
936Ext.menu.BaseItem = Ext.extend(Ext.Component, {
937    /**
938     * @property parentMenu
939     * @type Ext.menu.Menu
940     * The parent Menu of this Item.
941     */
942    /**
943     * @cfg {Function} handler
944     * A function that will handle the click event of this menu item (optional).
945     * The handler is passed the following parameters:<div class="mdetail-params"><ul>
946     * <li><code>b</code> : Item<div class="sub-desc">This menu Item.</div></li>
947     * <li><code>e</code> : EventObject<div class="sub-desc">The click event.</div></li>
948     * </ul></div>
949     */
950    /**
951     * @cfg {Object} scope
952     * The scope (<tt><b>this</b></tt> reference) in which the handler function will be called.
953     */
954    /**
955     * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
956     */
957    canActivate : false,
958    /**
959     * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
960     */
961    activeClass : "x-menu-item-active",
962    /**
963     * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
964     */
965    hideOnClick : true,
966    /**
967     * @cfg {Number} clickHideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 1)
968     */
969    clickHideDelay : 1,
970
971    // private
972    ctype : "Ext.menu.BaseItem",
973
974    // private
975    actionMode : "container",
976
977    initComponent : function(){
978        Ext.menu.BaseItem.superclass.initComponent.call(this);
979        this.addEvents(
980            /**
981             * @event click
982             * Fires when this item is clicked
983             * @param {Ext.menu.BaseItem} this
984             * @param {Ext.EventObject} e
985             */
986            'click',
987            /**
988             * @event activate
989             * Fires when this item is activated
990             * @param {Ext.menu.BaseItem} this
991             */
992            'activate',
993            /**
994             * @event deactivate
995             * Fires when this item is deactivated
996             * @param {Ext.menu.BaseItem} this
997             */
998            'deactivate'
999        );
1000        if(this.handler){
1001            this.on("click", this.handler, this.scope);
1002        }
1003    },
1004
1005    // private
1006    onRender : function(container, position){
1007        Ext.menu.BaseItem.superclass.onRender.apply(this, arguments);
1008        if(this.ownerCt && this.ownerCt instanceof Ext.menu.Menu){
1009            this.parentMenu = this.ownerCt;
1010        }else{
1011            this.container.addClass('x-menu-list-item');
1012            this.mon(this.el, {
1013                scope: this,
1014                click: this.onClick,
1015                mouseenter: this.activate,
1016                mouseleave: this.deactivate
1017            });
1018        }
1019    },
1020
1021    /**
1022     * Sets the function that will handle click events for this item (equivalent to passing in the {@link #handler}
1023     * config property).  If an existing handler is already registered, it will be unregistered for you.
1024     * @param {Function} handler The function that should be called on click
1025     * @param {Object} scope The scope (<code>this</code> reference) in which the handler function is executed. Defaults to this menu item.
1026     */
1027    setHandler : function(handler, scope){
1028        if(this.handler){
1029            this.un("click", this.handler, this.scope);
1030        }
1031        this.on("click", this.handler = handler, this.scope = scope);
1032    },
1033
1034    // private
1035    onClick : function(e){
1036        if(!this.disabled && this.fireEvent("click", this, e) !== false
1037                && (this.parentMenu && this.parentMenu.fireEvent("itemclick", this, e) !== false)){
1038            this.handleClick(e);
1039        }else{
1040            e.stopEvent();
1041        }
1042    },
1043
1044    // private
1045    activate : function(){
1046        if(this.disabled){
1047            return false;
1048        }
1049        var li = this.container;
1050        li.addClass(this.activeClass);
1051        this.region = li.getRegion().adjust(2, 2, -2, -2);
1052        this.fireEvent("activate", this);
1053        return true;
1054    },
1055
1056    // private
1057    deactivate : function(){
1058        this.container.removeClass(this.activeClass);
1059        this.fireEvent("deactivate", this);
1060    },
1061
1062    // private
1063    shouldDeactivate : function(e){
1064        return !this.region || !this.region.contains(e.getPoint());
1065    },
1066
1067    // private
1068    handleClick : function(e){
1069        var pm = this.parentMenu;
1070        if(this.hideOnClick){
1071            if(pm.floating){
1072                this.clickHideDelayTimer = pm.hide.defer(this.clickHideDelay, pm, [true]);
1073            }else{
1074                pm.deactivateActive();
1075            }
1076        }
1077    },
1078   
1079    beforeDestroy: function(){
1080        clearTimeout(this.clickHideDelayTimer);
1081        Ext.menu.BaseItem.superclass.beforeDestroy.call(this);   
1082    },
1083
1084    // private. Do nothing
1085    expandMenu : Ext.emptyFn,
1086
1087    // private. Do nothing
1088    hideMenu : Ext.emptyFn
1089});
1090Ext.reg('menubaseitem', Ext.menu.BaseItem);/**
1091 * @class Ext.menu.TextItem
1092 * @extends Ext.menu.BaseItem
1093 * Adds a static text string to a menu, usually used as either a heading or group separator.
1094 * @constructor
1095 * Creates a new TextItem
1096 * @param {Object/String} config If config is a string, it is used as the text to display, otherwise it
1097 * is applied as a config object (and should contain a <tt>text</tt> property).
1098 * @xtype menutextitem
1099 */
1100Ext.menu.TextItem = Ext.extend(Ext.menu.BaseItem, {
1101    /**
1102     * @cfg {String} text The text to display for this item (defaults to '')
1103     */
1104    /**
1105     * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
1106     */
1107    hideOnClick : false,
1108    /**
1109     * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
1110     */
1111    itemCls : "x-menu-text",
1112   
1113    constructor : function(config) {
1114        if (typeof config == 'string') {
1115            config = {
1116                text: config
1117            };
1118        }
1119        Ext.menu.TextItem.superclass.constructor.call(this, config);
1120    },
1121
1122    // private
1123    onRender : function() {
1124        var s = document.createElement("span");
1125        s.className = this.itemCls;
1126        s.innerHTML = this.text;
1127        this.el = s;
1128        Ext.menu.TextItem.superclass.onRender.apply(this, arguments);
1129    }
1130});
1131Ext.reg('menutextitem', Ext.menu.TextItem);/**
1132 * @class Ext.menu.Separator
1133 * @extends Ext.menu.BaseItem
1134 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
1135 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
1136 * @constructor
1137 * @param {Object} config Configuration options
1138 * @xtype menuseparator
1139 */
1140Ext.menu.Separator = Ext.extend(Ext.menu.BaseItem, {
1141    /**
1142     * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
1143     */
1144    itemCls : "x-menu-sep",
1145    /**
1146     * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
1147     */
1148    hideOnClick : false,
1149   
1150    /**
1151     * @cfg {String} activeClass
1152     * @hide
1153     */
1154    activeClass: '',
1155
1156    // private
1157    onRender : function(li){
1158        var s = document.createElement("span");
1159        s.className = this.itemCls;
1160        s.innerHTML = "&#160;";
1161        this.el = s;
1162        li.addClass("x-menu-sep-li");
1163        Ext.menu.Separator.superclass.onRender.apply(this, arguments);
1164    }
1165});
1166Ext.reg('menuseparator', Ext.menu.Separator);/**
1167 * @class Ext.menu.Item
1168 * @extends Ext.menu.BaseItem
1169 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
1170 * display items.  Item extends the base functionality of {@link Ext.menu.BaseItem} by adding menu-specific
1171 * activation and click handling.
1172 * @constructor
1173 * Creates a new Item
1174 * @param {Object} config Configuration options
1175 * @xtype menuitem
1176 */
1177Ext.menu.Item = Ext.extend(Ext.menu.BaseItem, {
1178    /**
1179     * @property menu
1180     * @type Ext.menu.Menu
1181     * The submenu associated with this Item if one was configured.
1182     */
1183    /**
1184     * @cfg {Mixed} menu (optional) Either an instance of {@link Ext.menu.Menu} or the config object for an
1185     * {@link Ext.menu.Menu} which acts as the submenu when this item is activated.
1186     */
1187    /**
1188     * @cfg {String} icon The path to an icon to display in this item (defaults to Ext.BLANK_IMAGE_URL).  If
1189     * icon is specified {@link #iconCls} should not be.
1190     */
1191    /**
1192     * @cfg {String} iconCls A CSS class that specifies a background image that will be used as the icon for
1193     * this item (defaults to '').  If iconCls is specified {@link #icon} should not be.
1194     */
1195    /**
1196     * @cfg {String} text The text to display in this item (defaults to '').
1197     */
1198    /**
1199     * @cfg {String} href The href attribute to use for the underlying anchor link (defaults to '#').
1200     */
1201    /**
1202     * @cfg {String} hrefTarget The target attribute to use for the underlying anchor link (defaults to '').
1203     */
1204    /**
1205     * @cfg {String} itemCls The default CSS class to use for menu items (defaults to 'x-menu-item')
1206     */
1207    itemCls : 'x-menu-item',
1208    /**
1209     * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
1210     */
1211    canActivate : true,
1212    /**
1213     * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
1214     */
1215    showDelay: 200,
1216   
1217    /**
1218     * @cfg {String} altText The altText to use for the icon, if it exists. Defaults to <tt>''</tt>.
1219     */
1220    altText: '',
1221   
1222    // doc'd in BaseItem
1223    hideDelay: 200,
1224
1225    // private
1226    ctype: 'Ext.menu.Item',
1227
1228    initComponent : function(){
1229        Ext.menu.Item.superclass.initComponent.call(this);
1230        if(this.menu){
1231            // If array of items, turn it into an object config so we
1232            // can set the ownerCt property in the config
1233            if (Ext.isArray(this.menu)){
1234                this.menu = { items: this.menu };
1235            }
1236           
1237            // An object config will work here, but an instance of a menu
1238            // will have already setup its ref's and have no effect
1239            if (Ext.isObject(this.menu)){
1240                this.menu.ownerCt = this;
1241            }
1242           
1243            this.menu = Ext.menu.MenuMgr.get(this.menu);
1244            this.menu.ownerCt = undefined;
1245        }
1246    },
1247
1248    // private
1249    onRender : function(container, position){
1250        if (!this.itemTpl) {
1251            this.itemTpl = Ext.menu.Item.prototype.itemTpl = new Ext.XTemplate(
1252                '<a id="{id}" class="{cls}" hidefocus="true" unselectable="on" href="{href}"',
1253                    '<tpl if="hrefTarget">',
1254                        ' target="{hrefTarget}"',
1255                    '</tpl>',
1256                 '>',
1257                     '<img alt="{altText}" src="{icon}" class="x-menu-item-icon {iconCls}"/>',
1258                     '<span class="x-menu-item-text">{text}</span>',
1259                 '</a>'
1260             );
1261        }
1262        var a = this.getTemplateArgs();
1263        this.el = position ? this.itemTpl.insertBefore(position, a, true) : this.itemTpl.append(container, a, true);
1264        this.iconEl = this.el.child('img.x-menu-item-icon');
1265        this.textEl = this.el.child('.x-menu-item-text');
1266        if(!this.href) { // if no link defined, prevent the default anchor event
1267            this.mon(this.el, 'click', Ext.emptyFn, null, { preventDefault: true });
1268        }
1269        Ext.menu.Item.superclass.onRender.call(this, container, position);
1270    },
1271
1272    getTemplateArgs: function() {
1273        return {
1274            id: this.id,
1275            cls: this.itemCls + (this.menu ?  ' x-menu-item-arrow' : '') + (this.cls ?  ' ' + this.cls : ''),
1276            href: this.href || '#',
1277            hrefTarget: this.hrefTarget,
1278            icon: this.icon || Ext.BLANK_IMAGE_URL,
1279            iconCls: this.iconCls || '',
1280            text: this.itemText||this.text||'&#160;',
1281            altText: this.altText || ''
1282        };
1283    },
1284
1285    /**
1286     * Sets the text to display in this menu item
1287     * @param {String} text The text to display
1288     */
1289    setText : function(text){
1290        this.text = text||'&#160;';
1291        if(this.rendered){
1292            this.textEl.update(this.text);
1293            this.parentMenu.layout.doAutoSize();
1294        }
1295    },
1296
1297    /**
1298     * Sets the CSS class to apply to the item's icon element
1299     * @param {String} cls The CSS class to apply
1300     */
1301    setIconClass : function(cls){
1302        var oldCls = this.iconCls;
1303        this.iconCls = cls;
1304        if(this.rendered){
1305            this.iconEl.replaceClass(oldCls, this.iconCls);
1306        }
1307    },
1308
1309    //private
1310    beforeDestroy: function(){
1311        clearTimeout(this.showTimer);
1312        clearTimeout(this.hideTimer);
1313        if (this.menu){
1314            delete this.menu.ownerCt;
1315            this.menu.destroy();
1316        }
1317        Ext.menu.Item.superclass.beforeDestroy.call(this);
1318    },
1319
1320    // private
1321    handleClick : function(e){
1322        if(!this.href){ // if no link defined, stop the event automatically
1323            e.stopEvent();
1324        }
1325        Ext.menu.Item.superclass.handleClick.apply(this, arguments);
1326    },
1327
1328    // private
1329    activate : function(autoExpand){
1330        if(Ext.menu.Item.superclass.activate.apply(this, arguments)){
1331            this.focus();
1332            if(autoExpand){
1333                this.expandMenu();
1334            }
1335        }
1336        return true;
1337    },
1338
1339    // private
1340    shouldDeactivate : function(e){
1341        if(Ext.menu.Item.superclass.shouldDeactivate.call(this, e)){
1342            if(this.menu && this.menu.isVisible()){
1343                return !this.menu.getEl().getRegion().contains(e.getPoint());
1344            }
1345            return true;
1346        }
1347        return false;
1348    },
1349
1350    // private
1351    deactivate : function(){
1352        Ext.menu.Item.superclass.deactivate.apply(this, arguments);
1353        this.hideMenu();
1354    },
1355
1356    // private
1357    expandMenu : function(autoActivate){
1358        if(!this.disabled && this.menu){
1359            clearTimeout(this.hideTimer);
1360            delete this.hideTimer;
1361            if(!this.menu.isVisible() && !this.showTimer){
1362                this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
1363            }else if (this.menu.isVisible() && autoActivate){
1364                this.menu.tryActivate(0, 1);
1365            }
1366        }
1367    },
1368
1369    // private
1370    deferExpand : function(autoActivate){
1371        delete this.showTimer;
1372        this.menu.show(this.container, this.parentMenu.subMenuAlign || 'tl-tr?', this.parentMenu);
1373        if(autoActivate){
1374            this.menu.tryActivate(0, 1);
1375        }
1376    },
1377
1378    // private
1379    hideMenu : function(){
1380        clearTimeout(this.showTimer);
1381        delete this.showTimer;
1382        if(!this.hideTimer && this.menu && this.menu.isVisible()){
1383            this.hideTimer = this.deferHide.defer(this.hideDelay, this);
1384        }
1385    },
1386
1387    // private
1388    deferHide : function(){
1389        delete this.hideTimer;
1390        if(this.menu.over){
1391            this.parentMenu.setActiveItem(this, false);
1392        }else{
1393            this.menu.hide();
1394        }
1395    }
1396});
1397Ext.reg('menuitem', Ext.menu.Item);/**
1398 * @class Ext.menu.CheckItem
1399 * @extends Ext.menu.Item
1400 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
1401 * @constructor
1402 * Creates a new CheckItem
1403 * @param {Object} config Configuration options
1404 * @xtype menucheckitem
1405 */
1406Ext.menu.CheckItem = Ext.extend(Ext.menu.Item, {
1407    /**
1408     * @cfg {String} group
1409     * All check items with the same group name will automatically be grouped into a single-select
1410     * radio button group (defaults to '')
1411     */
1412    /**
1413     * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
1414     */
1415    itemCls : "x-menu-item x-menu-check-item",
1416    /**
1417     * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
1418     */
1419    groupClass : "x-menu-group-item",
1420
1421    /**
1422     * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false).  Note that
1423     * if this checkbox is part of a radio group (group = true) only the first item in the group that is
1424     * initialized with checked = true will be rendered as checked.
1425     */
1426    checked: false,
1427
1428    // private
1429    ctype: "Ext.menu.CheckItem",
1430   
1431    initComponent : function(){
1432        Ext.menu.CheckItem.superclass.initComponent.call(this);
1433            this.addEvents(
1434                /**
1435                 * @event beforecheckchange
1436                 * Fires before the checked value is set, providing an opportunity to cancel if needed
1437                 * @param {Ext.menu.CheckItem} this
1438                 * @param {Boolean} checked The new checked value that will be set
1439                 */
1440                "beforecheckchange" ,
1441                /**
1442                 * @event checkchange
1443                 * Fires after the checked value has been set
1444                 * @param {Ext.menu.CheckItem} this
1445                 * @param {Boolean} checked The checked value that was set
1446                 */
1447                "checkchange"
1448            );
1449            /**
1450             * A function that handles the checkchange event.  The function is undefined by default, but if an implementation
1451             * is provided, it will be called automatically when the checkchange event fires.
1452             * @param {Ext.menu.CheckItem} this
1453             * @param {Boolean} checked The checked value that was set
1454             * @method checkHandler
1455             */
1456            if(this.checkHandler){
1457                this.on('checkchange', this.checkHandler, this.scope);
1458            }
1459            Ext.menu.MenuMgr.registerCheckable(this);
1460    },
1461
1462    // private
1463    onRender : function(c){
1464        Ext.menu.CheckItem.superclass.onRender.apply(this, arguments);
1465        if(this.group){
1466            this.el.addClass(this.groupClass);
1467        }
1468        if(this.checked){
1469            this.checked = false;
1470            this.setChecked(true, true);
1471        }
1472    },
1473
1474    // private
1475    destroy : function(){
1476        Ext.menu.MenuMgr.unregisterCheckable(this);
1477        Ext.menu.CheckItem.superclass.destroy.apply(this, arguments);
1478    },
1479
1480    /**
1481     * Set the checked state of this item
1482     * @param {Boolean} checked The new checked value
1483     * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
1484     */
1485    setChecked : function(state, suppressEvent){
1486        var suppress = suppressEvent === true;
1487        if(this.checked != state && (suppress || this.fireEvent("beforecheckchange", this, state) !== false)){
1488            Ext.menu.MenuMgr.onCheckChange(this, state);
1489            if(this.container){
1490                this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
1491            }
1492            this.checked = state;
1493            if(!suppress){
1494                this.fireEvent("checkchange", this, state);
1495            }
1496        }
1497    },
1498
1499    // private
1500    handleClick : function(e){
1501       if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
1502           this.setChecked(!this.checked);
1503       }
1504       Ext.menu.CheckItem.superclass.handleClick.apply(this, arguments);
1505    }
1506});
1507Ext.reg('menucheckitem', Ext.menu.CheckItem);/**
1508 * @class Ext.menu.DateMenu
1509 * @extends Ext.menu.Menu
1510 * <p>A menu containing an {@link Ext.DatePicker} Component.</p>
1511 * <p>Notes:</p><div class="mdetail-params"><ul>
1512 * <li>Although not listed here, the <b>constructor</b> for this class
1513 * accepts all of the configuration options of <b>{@link Ext.DatePicker}</b>.</li>
1514 * <li>If subclassing DateMenu, any configuration options for the DatePicker must be
1515 * applied to the <tt><b>initialConfig</b></tt> property of the DateMenu.
1516 * Applying {@link Ext.DatePicker DatePicker} configuration settings to
1517 * <b><tt>this</tt></b> will <b>not</b> affect the DatePicker's configuration.</li>
1518 * </ul></div>
1519 * @xtype datemenu
1520 */
1521 Ext.menu.DateMenu = Ext.extend(Ext.menu.Menu, {
1522    /**
1523     * @cfg {Boolean} enableScrolling
1524     * @hide
1525     */
1526    enableScrolling : false,
1527    /**
1528     * @cfg {Function} handler
1529     * Optional. A function that will handle the select event of this menu.
1530     * The handler is passed the following parameters:<div class="mdetail-params"><ul>
1531     * <li><code>picker</code> : DatePicker<div class="sub-desc">The Ext.DatePicker.</div></li>
1532     * <li><code>date</code> : Date<div class="sub-desc">The selected date.</div></li>
1533     * </ul></div>
1534     */
1535    /**
1536     * @cfg {Object} scope
1537     * The scope (<tt><b>this</b></tt> reference) in which the <code>{@link #handler}</code>
1538     * function will be called.  Defaults to this DateMenu instance.
1539     */   
1540    /**
1541     * @cfg {Boolean} hideOnClick
1542     * False to continue showing the menu after a date is selected, defaults to true.
1543     */
1544    hideOnClick : true,
1545   
1546    /**
1547     * @cfg {String} pickerId
1548     * An id to assign to the underlying date picker. Defaults to <tt>null</tt>.
1549     */
1550    pickerId : null,
1551   
1552    /**
1553     * @cfg {Number} maxHeight
1554     * @hide
1555     */
1556    /**
1557     * @cfg {Number} scrollIncrement
1558     * @hide
1559     */
1560    /**
1561     * The {@link Ext.DatePicker} instance for this DateMenu
1562     * @property picker
1563     * @type DatePicker
1564     */
1565    cls : 'x-date-menu',
1566   
1567    /**
1568     * @event click
1569     * @hide
1570     */
1571   
1572    /**
1573     * @event itemclick
1574     * @hide
1575     */
1576
1577    initComponent : function(){
1578        this.on('beforeshow', this.onBeforeShow, this);
1579        if(this.strict = (Ext.isIE7 && Ext.isStrict)){
1580            this.on('show', this.onShow, this, {single: true, delay: 20});
1581        }
1582        Ext.apply(this, {
1583            plain: true,
1584            showSeparator: false,
1585            items: this.picker = new Ext.DatePicker(Ext.applyIf({
1586                internalRender: this.strict || !Ext.isIE,
1587                ctCls: 'x-menu-date-item',
1588                id: this.pickerId
1589            }, this.initialConfig))
1590        });
1591        this.picker.purgeListeners();
1592        Ext.menu.DateMenu.superclass.initComponent.call(this);
1593        /**
1594         * @event select
1595         * Fires when a date is selected from the {@link #picker Ext.DatePicker}
1596         * @param {DatePicker} picker The {@link #picker Ext.DatePicker}
1597         * @param {Date} date The selected date
1598         */
1599        this.relayEvents(this.picker, ['select']);
1600        this.on('show', this.picker.focus, this.picker);
1601        this.on('select', this.menuHide, this);
1602        if(this.handler){
1603            this.on('select', this.handler, this.scope || this);
1604        }
1605    },
1606
1607    menuHide : function() {
1608        if(this.hideOnClick){
1609            this.hide(true);
1610        }
1611    },
1612
1613    onBeforeShow : function(){
1614        if(this.picker){
1615            this.picker.hideMonthPicker(true);
1616        }
1617    },
1618
1619    onShow : function(){
1620        var el = this.picker.getEl();
1621        el.setWidth(el.getWidth()); //nasty hack for IE7 strict mode
1622    }
1623 });
1624 Ext.reg('datemenu', Ext.menu.DateMenu);
1625 /**
1626 * @class Ext.menu.ColorMenu
1627 * @extends Ext.menu.Menu
1628 * <p>A menu containing a {@link Ext.ColorPalette} Component.</p>
1629 * <p>Notes:</p><div class="mdetail-params"><ul>
1630 * <li>Although not listed here, the <b>constructor</b> for this class
1631 * accepts all of the configuration options of <b>{@link Ext.ColorPalette}</b>.</li>
1632 * <li>If subclassing ColorMenu, any configuration options for the ColorPalette must be
1633 * applied to the <tt><b>initialConfig</b></tt> property of the ColorMenu.
1634 * Applying {@link Ext.ColorPalette ColorPalette} configuration settings to
1635 * <b><tt>this</tt></b> will <b>not</b> affect the ColorPalette's configuration.</li>
1636 * </ul></div> *
1637 * @xtype colormenu
1638 */
1639 Ext.menu.ColorMenu = Ext.extend(Ext.menu.Menu, {
1640    /**
1641     * @cfg {Boolean} enableScrolling
1642     * @hide
1643     */
1644    enableScrolling : false,
1645    /**
1646     * @cfg {Function} handler
1647     * Optional. A function that will handle the select event of this menu.
1648     * The handler is passed the following parameters:<div class="mdetail-params"><ul>
1649     * <li><code>palette</code> : ColorPalette<div class="sub-desc">The {@link #palette Ext.ColorPalette}.</div></li>
1650     * <li><code>color</code> : String<div class="sub-desc">The 6-digit color hex code (without the # symbol).</div></li>
1651     * </ul></div>
1652     */
1653    /**
1654     * @cfg {Object} scope
1655     * The scope (<tt><b>this</b></tt> reference) in which the <code>{@link #handler}</code>
1656     * function will be called.  Defaults to this ColorMenu instance.
1657     */   
1658   
1659    /**
1660     * @cfg {Boolean} hideOnClick
1661     * False to continue showing the menu after a color is selected, defaults to true.
1662     */
1663    hideOnClick : true,
1664   
1665    cls : 'x-color-menu',
1666   
1667    /**
1668     * @cfg {String} paletteId
1669     * An id to assign to the underlying color palette. Defaults to <tt>null</tt>.
1670     */
1671    paletteId : null,
1672   
1673    /**
1674     * @cfg {Number} maxHeight
1675     * @hide
1676     */
1677    /**
1678     * @cfg {Number} scrollIncrement
1679     * @hide
1680     */
1681    /**
1682     * @property palette
1683     * @type ColorPalette
1684     * The {@link Ext.ColorPalette} instance for this ColorMenu
1685     */
1686   
1687   
1688    /**
1689     * @event click
1690     * @hide
1691     */
1692   
1693    /**
1694     * @event itemclick
1695     * @hide
1696     */
1697   
1698    initComponent : function(){
1699        Ext.apply(this, {
1700            plain: true,
1701            showSeparator: false,
1702            items: this.palette = new Ext.ColorPalette(Ext.applyIf({
1703                id: this.paletteId
1704            }, this.initialConfig))
1705        });
1706        this.palette.purgeListeners();
1707        Ext.menu.ColorMenu.superclass.initComponent.call(this);
1708        /**
1709         * @event select
1710         * Fires when a color is selected from the {@link #palette Ext.ColorPalette}
1711         * @param {Ext.ColorPalette} palette The {@link #palette Ext.ColorPalette}
1712             * @param {String} color The 6-digit color hex code (without the # symbol)
1713         */
1714        this.relayEvents(this.palette, ['select']);
1715        this.on('select', this.menuHide, this);
1716        if(this.handler){
1717            this.on('select', this.handler, this.scope || this);
1718        }
1719    },
1720
1721    menuHide : function(){
1722        if(this.hideOnClick){
1723            this.hide(true);
1724        }
1725    }
1726});
1727Ext.reg('colormenu', Ext.menu.ColorMenu);
Note: See TracBrowser for help on using the repository browser.