Focus.js
上传用户:dawnssy
上传日期:2022-08-06
资源大小:9345k
文件大小:23k
源码类别:

JavaScript

开发平台:

JavaScript

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