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