source: trunk/web/addons/job_monarch/lib/extjs-30/examples/ux/Focus.js @ 625

Last change on this file since 625 was 625, checked in by ramonb, 15 years ago

lib/extjs-30:

  • new ExtJS 3.0
File size: 22.9 KB
Line 
1/*!
2 * Ext JS Library 3.0.0
3 * Copyright(c) 2006-2009 Ext JS, LLC
4 * licensing@extjs.com
5 * http://www.extjs.com/license
6 */
7(function(){
8Ext.ns('Ext.a11y');
9
10Ext.a11y.Frame = Ext.extend(Object, {
11    initialized: false,
12   
13    constructor: function(size, color){
14        this.setSize(size || 1);
15        this.setColor(color || '15428B');
16    },
17   
18    init: function(){
19        if (!this.initialized) {
20            this.sides = [];
21           
22            var s, i;
23           
24            this.ct = Ext.DomHelper.append(document.body, {
25                cls: 'x-a11y-focusframe'
26            }, true);
27           
28            for (i = 0; i < 4; i++) {
29                s = Ext.DomHelper.append(this.ct, {
30                    cls: 'x-a11y-focusframe-side',
31                    style: 'background-color: #' + this.color
32                }, true);
33                s.visibilityMode = Ext.Element.DISPLAY;
34                this.sides.push(s);
35            }
36           
37            this.frameTask = new Ext.util.DelayedTask(function(el){
38                var newEl = Ext.get(el);
39                if (newEl != this.curEl) {
40                    var w = newEl.getWidth();
41                    var h = newEl.getHeight();
42                    this.sides[0].show().setSize(w, this.size).anchorTo(el, 'tl', [0, -1]);
43                    this.sides[2].show().setSize(w, this.size).anchorTo(el, 'bl', [0, -1]);
44                    this.sides[1].show().setSize(this.size, h).anchorTo(el, 'tr', [-1, 0]);
45                    this.sides[3].show().setSize(this.size, h).anchorTo(el, 'tl', [-1, 0]);
46                    this.curEl = newEl;
47                }
48            }, this);
49           
50            this.unframeTask = new Ext.util.DelayedTask(function(){
51                if (this.initialized) {
52                    this.sides[0].hide();
53                    this.sides[1].hide();
54                    this.sides[2].hide();
55                    this.sides[3].hide();
56                    this.curEl = null;
57                }
58            }, this);
59            this.initialized = true;
60        }
61    },
62   
63    frame: function(el){
64        this.init();
65        this.unframeTask.cancel();
66        this.frameTask.delay(2, false, false, [el]);
67    },
68   
69    unframe: function(){
70        this.init();
71        this.unframeTask.delay(2);
72    },
73   
74    setSize: function(size){
75        this.size = size;
76    },
77   
78    setColor: function(color){
79        this.color = color;
80    }
81});
82
83Ext.a11y.FocusFrame = new Ext.a11y.Frame(2, '15428B');
84Ext.a11y.RelayFrame = new Ext.a11y.Frame(1, '6B8CBF');
85
86Ext.a11y.Focusable = Ext.extend(Ext.util.Observable, {
87    constructor: function(el, relayTo, noFrame, frameEl){
88        Ext.a11y.Focusable.superclass.constructor.call(this);
89       
90        this.addEvents('focus', 'blur', 'left', 'right', 'up', 'down', 'esc', 'enter', 'space');
91       
92        if (el instanceof Ext.Component) {
93            this.el = el.el;
94            this.setComponent(el);
95        }
96        else {
97            this.el = Ext.get(el);
98            this.setComponent(null);
99        }
100       
101        this.setRelayTo(relayTo)
102        this.setNoFrame(noFrame);
103        this.setFrameEl(frameEl);
104       
105        this.init();
106       
107        Ext.a11y.FocusMgr.register(this);
108    },
109   
110    init: function(){
111        this.el.dom.tabIndex = '1';
112        this.el.addClass('x-a11y-focusable');
113        this.el.on({
114            focus: this.onFocus,
115            blur: this.onBlur,
116            keydown: this.onKeyDown,
117            scope: this
118        });
119    },
120   
121    setRelayTo: function(relayTo){
122        this.relayTo = relayTo ? Ext.a11y.FocusMgr.get(relayTo) : null;
123    },
124   
125    setNoFrame: function(noFrame){
126        this.noFrame = (noFrame === true) ? true : false;
127    },
128   
129    setFrameEl: function(frameEl){
130        this.frameEl = frameEl && Ext.get(frameEl) || this.el;
131    },
132   
133    setComponent: function(cmp){
134        this.component = cmp || null;
135    },
136   
137    onKeyDown: function(e, t){
138        var k = e.getKey(), SK = Ext.a11y.Focusable.SpecialKeys, ret, tf;
139       
140        tf = (t !== this.el.dom) ? Ext.a11y.FocusMgr.get(t, true) : this;
141        if (!tf) {
142            // this can happen when you are on a focused item within a panel body
143            // that is not a Ext.a11y.Focusable
144            tf = Ext.a11y.FocusMgr.get(Ext.fly(t).parent('.x-a11y-focusable'));
145        }
146       
147        if (SK[k] !== undefined) {
148            ret = this.fireEvent(SK[k], e, t, tf, this);
149        }
150        if (ret === false || this.fireEvent('keydown', e, t, tf, this) === false) {
151            e.stopEvent();
152        }
153    },
154   
155    focus: function(){
156        this.el.dom.focus();
157    },
158   
159    blur: function(){
160        this.el.dom.blur();
161    },
162   
163    onFocus: function(e, t){
164        this.el.addClass('x-a11y-focused');
165        if (this.relayTo) {
166            this.relayTo.el.addClass('x-a11y-focused-relay');
167            if (!this.relayTo.noFrame) {
168                Ext.a11y.FocusFrame.frame(this.relayTo.frameEl);
169            }
170            if (!this.noFrame) {
171                Ext.a11y.RelayFrame.frame(this.frameEl);
172            }
173        }
174        else {
175            if (!this.noFrame) {
176                Ext.a11y.FocusFrame.frame(this.frameEl);
177            }
178        }
179       
180        this.fireEvent('focus', e, t, this);
181    },
182   
183    onBlur: function(e, t){
184        if (this.relayTo) {
185            this.relayTo.el.removeClass('x-a11y-focused-relay');
186            Ext.a11y.RelayFrame.unframe();
187        }
188        this.el.removeClass('x-a11y-focused');
189        Ext.a11y.FocusFrame.unframe();
190        this.fireEvent('blur', e, t, this);
191    },
192   
193    destroy: function(){
194        this.el.un('keydown', this.onKeyDown);
195        this.el.un('focus', this.onFocus);
196        this.el.un('blur', this.onBlur);
197        this.el.removeClass('x-a11y-focusable');
198        this.el.removeClass('x-a11y-focused');
199        if (this.relayTo) {
200            this.relayTo.el.removeClass('x-a11y-focused-relay');
201        }
202    }
203});
204
205Ext.a11y.FocusItem = Ext.extend(Object, {
206    constructor: function(el, enableTabbing){
207        Ext.a11y.FocusItem.superclass.constructor.call(this);
208       
209        this.el = Ext.get(el);
210        this.fi = new Ext.a11y.Focusable(el);
211        this.fi.setComponent(this);
212       
213        this.fi.on('tab', this.onTab, this);
214       
215        this.enableTabbing = enableTabbing === true ? true : false;
216    },
217   
218    getEnterItem: function(){
219        if (this.enableTabbing) {
220            var items = this.getFocusItems();
221            if (items && items.length) {
222                return items[0];
223            }
224        }
225    },
226   
227    getFocusItems: function(){
228        if (this.enableTabbing) {
229            return this.el.query('a, button, input, select');
230        }
231        return null;
232    },
233   
234    onTab: function(e, t){
235        var items = this.getFocusItems(), i;
236       
237        if (items && items.length && (i = items.indexOf(t)) !== -1) {
238            if (e.shiftKey && i > 0) {
239                e.stopEvent();
240                items[i - 1].focus();
241                Ext.a11y.FocusFrame.frame.defer(20, Ext.a11y.FocusFrame, [this.el]);
242                return;
243            }
244            else 
245                if (!e.shiftKey && i < items.length - 1) {
246                    e.stopEvent();
247                    items[i + 1].focus();
248                    Ext.a11y.FocusFrame.frame.defer(20, Ext.a11y.FocusFrame, [this.el]);
249                    return;
250                }
251        }
252    },
253   
254    focus: function(){
255        if (this.enableTabbing) {
256            var items = this.getFocusItems();
257            if (items && items.length) {
258                items[0].focus();
259                Ext.a11y.FocusFrame.frame.defer(20, Ext.a11y.FocusFrame, [this.el]);
260                return;
261            }
262        }
263        this.fi.focus();
264    },
265   
266    blur: function(){
267        this.fi.blur();
268    }
269});
270
271Ext.a11y.FocusMgr = function(){
272    var all = new Ext.util.MixedCollection();
273   
274    return {
275        register: function(f){
276            all.add(f.el && Ext.id(f.el), f);
277        },
278       
279        unregister: function(f){
280            all.remove(f);
281        },
282       
283        get: function(el, noCreate){
284            return all.get(Ext.id(el)) || (noCreate ? false : new Ext.a11y.Focusable(el));
285        },
286       
287        all: all
288    }
289}();
290
291Ext.a11y.Focusable.SpecialKeys = {};
292Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.LEFT] = 'left';
293Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.RIGHT] = 'right';
294Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.DOWN] = 'down';
295Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.UP] = 'up';
296Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.ESC] = 'esc';
297Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.ENTER] = 'enter';
298Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.SPACE] = 'space';
299Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.TAB] = 'tab';
300
301// we use the new observeClass method to fire our new initFocus method on components
302Ext.util.Observable.observeClass(Ext.Component);
303Ext.Component.on('render', function(cmp){
304    cmp.initFocus();
305    cmp.initARIA();
306});
307Ext.override(Ext.Component, {
308    initFocus: Ext.emptyFn,
309    initARIA: Ext.emptyFn
310});
311
312Ext.override(Ext.Container, {
313    isFocusable: true,
314    noFocus: false,
315   
316    // private
317    initFocus: function(){
318        if (!this.fi && !this.noFocus) {
319            this.fi = new Ext.a11y.Focusable(this);
320        }
321        this.mon(this.fi, {
322            focus: this.onFocus,
323            blur: this.onBlur,
324            tab: this.onTab,
325            enter: this.onEnter,
326            esc: this.onEsc,
327            scope: this
328        });
329       
330        if (this.hidden) {
331            this.isFocusable = false;
332        }
333       
334        this.on('show', function(){
335            this.isFocusable = true;
336        }, this);
337        this.on('hide', function(){
338            this.isFocusable = false;
339        }, this);
340    },
341   
342    focus: function(){
343        this.fi.focus();
344    },
345   
346    blur: function(){
347        this.fi.blur();
348    },
349   
350    enter: function(){
351        var eitem = this.getEnterItem();
352        if (eitem) {
353            eitem.focus();
354        }
355    },
356   
357    onFocus: Ext.emptyFn,
358    onBlur: Ext.emptyFn,
359   
360    onTab: function(e, t, tf){
361        var rf = tf.relayTo || tf;
362        if (rf.component && rf.component !== this) {
363            e.stopEvent();
364            var item = e.shiftKey ? this.getPreviousFocus(rf.component) : this.getNextFocus(rf.component);
365            item.focus();
366        }
367    },
368   
369    onEnter: function(e, t, tf){
370        // check to see if enter is pressed while "on" the panel
371        if (tf.component && tf.component === this) {
372            e.stopEvent();
373            this.enter();
374        }
375        e.stopPropagation();
376    },
377   
378    onEsc: function(e, t){
379        e.preventDefault();
380       
381        // check to see if esc is pressed while "inside" the panel
382        // or while "on" the panel
383        if (t === this.el.dom) {
384            // "on" the panel, check if this panel has an owner panel and focus that
385            // we dont stop the event in this case so that this same check will be
386            // done for this ownerCt
387            if (this.ownerCt) {
388                this.ownerCt.focus();
389            }
390        }
391        else {
392            // we were inside the panel when esc was pressed,
393            // so go back "on" the panel
394            if (this.ownerCt && this.ownerCt.isFocusable) {
395                var si = this.ownerCt.getFocusItems();
396               
397                if (si && si.getCount() > 1) {
398                    e.stopEvent();
399                }
400            }
401            this.focus();
402        }
403    },
404   
405    getFocusItems: function(){
406        return this.items &&
407        this.items.filterBy(function(o){
408            return o.isFocusable;
409        }) ||
410        null;
411    },
412   
413    getEnterItem: function(){
414        var ci = this.getFocusItems(), length = ci ? ci.getCount() : 0;
415       
416        if (length === 1) {
417            return ci.first().getEnterItem && ci.first().getEnterItem() || ci.first();
418        }
419        else 
420            if (length > 1) {
421                return ci.first();
422            }
423    },
424   
425    getNextFocus: function(current){
426        var items = this.getFocusItems(), next = current, i = items.indexOf(current), length = items.getCount();
427       
428        if (i === length - 1) {
429            next = items.first();
430        }
431        else {
432            next = items.get(i + 1);
433        }
434        return next;
435    },
436   
437    getPreviousFocus: function(current){
438        var items = this.getFocusItems(), prev = current, i = items.indexOf(current), length = items.getCount();
439       
440        if (i === 0) {
441            prev = items.last();
442        }
443        else {
444            prev = items.get(i - 1);
445        }
446        return prev;
447    },
448   
449    getFocusable : function() {
450        return this.fi;
451    }
452});
453
454Ext.override(Ext.Panel, {
455    /**
456     * @cfg {Boolean} enableTabbing <tt>true</tt> to enable tabbing. Default is <tt>false</tt>.
457     */       
458    getFocusItems: function(){
459        // items gets all the items inside the body
460        var items = Ext.Panel.superclass.getFocusItems.call(this), bodyFocus = null;
461       
462        if (!items) {
463            items = new Ext.util.MixedCollection();
464            this.bodyFocus = this.bodyFocus || new Ext.a11y.FocusItem(this.body, this.enableTabbing);
465            items.add('body', this.bodyFocus);
466        }
467        // but panels can also have tbar, bbar, fbar
468        if (this.tbar && this.topToolbar) {
469            items.insert(0, this.topToolbar);
470        }
471        if (this.bbar && this.bottomToolbar) {
472            items.add(this.bottomToolbar);
473        }
474        if (this.fbar) {
475            items.add(this.fbar);
476        }
477       
478        return items;
479    }
480});
481
482Ext.override(Ext.TabPanel, {
483    // private
484    initFocus: function(){
485        Ext.TabPanel.superclass.initFocus.call(this);
486        this.mon(this.fi, {
487            left: this.onLeft,
488            right: this.onRight,
489            scope: this
490        });
491    },
492   
493    onLeft: function(e){
494        if (!this.activeTab) {
495            return;
496        }
497        e.stopEvent();
498        var prev = this.items.itemAt(this.items.indexOf(this.activeTab) - 1);
499        if (prev) {
500            this.setActiveTab(prev);
501        }
502        return false;
503    },
504   
505    onRight: function(e){
506        if (!this.activeTab) {
507            return;
508        }
509        e.stopEvent();
510        var next = this.items.itemAt(this.items.indexOf(this.activeTab) + 1);
511        if (next) {
512            this.setActiveTab(next);
513        }
514        return false;
515    }
516});
517
518Ext.override(Ext.tree.TreeNodeUI, {
519    // private
520    focus: function(){
521        this.node.getOwnerTree().bodyFocus.focus();
522    }
523});
524
525Ext.override(Ext.tree.TreePanel, {
526    // private
527    afterRender : function(){
528        Ext.tree.TreePanel.superclass.afterRender.call(this);
529        this.root.render();
530        if(!this.rootVisible){
531            this.root.renderChildren();
532        }
533        this.bodyFocus = new Ext.a11y.FocusItem(this.body.down('.x-tree-root-ct'));
534        this.bodyFocus.fi.setFrameEl(this.body);
535    } 
536});
537
538Ext.override(Ext.grid.GridPanel, {
539    initFocus: function(){
540        Ext.grid.GridPanel.superclass.initFocus.call(this);
541        this.bodyFocus = new Ext.a11y.FocusItem(this.view.focusEl);
542        this.bodyFocus.fi.setFrameEl(this.body);
543    }
544});
545
546Ext.override(Ext.Button, {
547    isFocusable: true,
548    noFocus: false,
549   
550    initFocus: function(){
551        Ext.Button.superclass.initFocus.call(this);
552        this.fi = this.fi || new Ext.a11y.Focusable(this.btnEl, null, null, this.el);
553        this.fi.setComponent(this);
554       
555        this.mon(this.fi, {
556            focus: this.onFocus,
557            blur: this.onBlur,
558            scope: this
559        });
560       
561        if (this.menu) {
562            this.mon(this.fi, 'down', this.showMenu, this);
563            this.on('menuhide', this.focus, this);
564        }
565       
566        if (this.hidden) {
567            this.isFocusable = false;
568        }
569       
570        this.on('show', function(){
571            this.isFocusable = true;
572        }, this);
573        this.on('hide', function(){
574            this.isFocusable = false;
575        }, this);
576    },
577   
578    focus: function(){
579        this.fi.focus();
580    },
581   
582    blur: function(){
583        this.fi.blur();
584    },
585   
586    onFocus: function(){
587        if (!this.disabled) {
588            this.el.addClass("x-btn-focus");
589        }
590    },
591   
592    onBlur: function(){
593        this.el.removeClass("x-btn-focus");
594    }
595});
596
597Ext.override(Ext.Toolbar, {
598    initFocus: function(){
599        Ext.Toolbar.superclass.initFocus.call(this);
600        this.mon(this.fi, {
601            left: this.onLeft,
602            right: this.onRight,
603            scope: this
604        });
605       
606        this.on('focus', this.onButtonFocus, this, {
607            stopEvent: true
608        });
609    },
610   
611    addItem: function(item){
612        Ext.Toolbar.superclass.add.apply(this, arguments);
613        if (item.rendered && item.fi !== undefined) {
614            item.fi.setRelayTo(this.el);
615            this.relayEvents(item.fi, ['focus']);
616        }
617        else {
618            item.on('render', function(){
619                if (item.fi !== undefined) {
620                    item.fi.setRelayTo(this.el);
621                    this.relayEvents(item.fi, ['focus']);
622                }
623            }, this, {
624                single: true
625            });
626        }
627        return item;
628    },
629   
630    onFocus: function(){
631        var items = this.getFocusItems();
632        if (items && items.getCount() > 0) {
633            if (this.lastFocus && items.indexOf(this.lastFocus) !== -1) {
634                this.lastFocus.focus();
635            }
636            else {
637                items.first().focus();
638            }
639        }
640    },
641   
642    onButtonFocus: function(e, t, tf){
643        this.lastFocus = tf.component || null;
644    },
645   
646    onLeft: function(e, t, tf){
647        e.stopEvent();
648        this.getPreviousFocus(tf.component).focus();
649    },
650   
651    onRight: function(e, t, tf){
652        e.stopEvent();
653        this.getNextFocus(tf.component).focus();
654    },
655   
656    getEnterItem: Ext.emptyFn,
657    onTab: Ext.emptyFn,
658    onEsc: Ext.emptyFn
659});
660
661Ext.override(Ext.menu.BaseItem, {
662    initFocus: function(){
663        this.fi = new Ext.a11y.Focusable(this, this.parentMenu && this.parentMenu.el || null, true);
664    }
665});
666
667Ext.override(Ext.menu.Menu, {
668    initFocus: function(){
669        this.fi = new Ext.a11y.Focusable(this);
670        this.focusEl = this.fi;
671    }
672});
673
674Ext.a11y.WindowMgr = new Ext.WindowGroup();
675
676Ext.apply(Ext.WindowMgr, {
677    bringToFront: function(win){
678        Ext.a11y.WindowMgr.bringToFront.call(this, win);
679        if (win.modal) {
680            win.enter();
681        }
682        else {
683            win.focus();
684        }
685    }
686});
687
688Ext.override(Ext.Window, {
689    initFocus: function(){
690        Ext.Window.superclass.initFocus.call(this);
691        this.on('beforehide', function(){
692            Ext.a11y.RelayFrame.unframe();
693            Ext.a11y.FocusFrame.unframe();
694        });
695    }
696});
697
698Ext.override(Ext.form.Field, {
699    isFocusable: true,
700    noFocus: false,
701   
702    initFocus: function(){
703        this.fi = this.fi || new Ext.a11y.Focusable(this, null, true);
704       
705        Ext.form.Field.superclass.initFocus.call(this);
706       
707        if (this.hidden) {
708            this.isFocusable = false;
709        }
710       
711        this.on('show', function(){
712            this.isFocusable = true;
713        }, this);
714        this.on('hide', function(){
715            this.isFocusable = false;
716        }, this);
717    }
718});
719
720Ext.override(Ext.FormPanel, {
721    initFocus: function(){
722        Ext.FormPanel.superclass.initFocus.call(this);
723        this.on('focus', this.onFieldFocus, this, {
724            stopEvent: true
725        });
726    },
727   
728    // private
729    createForm: function(){
730        delete this.initialConfig.listeners;
731        var form = new Ext.form.BasicForm(null, this.initialConfig);
732        form.afterMethod('add', this.formItemAdd, this);
733        return form;
734    },
735   
736    formItemAdd: function(item){
737        item.on('render', function(field){
738            field.fi.setRelayTo(this.el);
739            this.relayEvents(field.fi, ['focus']);
740        }, this, {
741            single: true
742        });
743    },
744   
745    onFocus: function(){
746        var items = this.getFocusItems();
747        if (items && items.getCount() > 0) {
748            if (this.lastFocus && items.indexOf(this.lastFocus) !== -1) {
749                this.lastFocus.focus();
750            }
751            else {
752                items.first().focus();
753            }
754        }
755    },
756   
757    onFieldFocus: function(e, t, tf){
758        this.lastFocus = tf.component || null;
759    },
760   
761    onTab: function(e, t, tf){
762        if (tf.relayTo.component === this) {
763            var item = e.shiftKey ? this.getPreviousFocus(tf.component) : this.getNextFocus(tf.component);
764           
765            if (item) {
766                ev.stopEvent();
767                item.focus();
768                return;
769            }
770        }
771        Ext.FormPanel.superclass.onTab.apply(this, arguments);
772    },
773   
774    getNextFocus: function(current){
775        var items = this.getFocusItems(), i = items.indexOf(current), length = items.getCount();
776       
777        return (i < length - 1) ? items.get(i + 1) : false;
778    },
779   
780    getPreviousFocus: function(current){
781        var items = this.getFocusItems(), i = items.indexOf(current), length = items.getCount();
782       
783        return (i > 0) ? items.get(i - 1) : false;
784    }
785});
786
787Ext.override(Ext.Viewport, {
788    initFocus: function(){
789        Ext.Viewport.superclass.initFocus.apply(this);
790        this.mon(Ext.get(document), 'focus', this.focus, this);
791        this.mon(Ext.get(document), 'blur', this.blur, this);
792        this.fi.setNoFrame(true);
793    },
794   
795    onTab: function(e, t, tf, f){
796        e.stopEvent();
797       
798        if (tf === f) {
799            items = this.getFocusItems();
800            if (items && items.getCount() > 0) {
801                items.first().focus();
802            }
803        }
804        else {
805            var rf = tf.relayTo || tf;
806            var item = e.shiftKey ? this.getPreviousFocus(rf.component) : this.getNextFocus(rf.component);
807            item.focus();
808        }
809    }
810});
811   
812})();
Note: See TracBrowser for help on using the repository browser.