ext-all-debug.js
上传用户:shuoshiled
上传日期:2018-01-28
资源大小:10124k
文件大小:2341k
源码类别:

中间件编程

开发平台:

JavaScript

  1.             }
  2.         }
  3.     }
  4. });
  5. Ext.Container.LAYOUTS['menu'] = Ext.layout.MenuLayout;
  6. /**
  7.  * @class Ext.menu.Menu
  8.  * @extends Ext.Container
  9.  * <p>A menu object.  This is the container to which you may add menu items.  Menu can also serve as a base class
  10.  * when you want a specialized menu based off of another component (like {@link Ext.menu.DateMenu} for example).</p>
  11.  * <p>Menus may contain either {@link Ext.menu.Item menu items}, or general {@link Ext.Component Component}s.</p>
  12.  * <p>To make a contained general {@link Ext.Component Component} line up with other {@link Ext.menu.Item menu items}
  13.  * specify <tt>iconCls: 'no-icon'</tt>.  This reserves a space for an icon, and indents the Component in line
  14.  * with the other menu items.  See {@link Ext.form.ComboBox}.{@link Ext.form.ComboBox#getListParent getListParent}
  15.  * for an example.</p>
  16.  * <p>By default, Menus are absolutely positioned, floating Components. By configuring a Menu with
  17.  * <b><tt>{@link #floating}:false</tt></b>, a Menu may be used as child of a Container.</p>
  18.  *
  19.  * @xtype menu
  20.  */
  21. Ext.menu.Menu = Ext.extend(Ext.Container, {
  22.     /**
  23.      * @cfg {Object} defaults
  24.      * A config object that will be applied to all items added to this container either via the {@link #items}
  25.      * config or via the {@link #add} method.  The defaults config can contain any number of
  26.      * name/value property pairs to be added to each item, and should be valid for the types of items
  27.      * being added to the menu.
  28.      */
  29.     /**
  30.      * @cfg {Mixed} items
  31.      * An array of items to be added to this menu. Menus may contain either {@link Ext.menu.Item menu items},
  32.      * or general {@link Ext.Component Component}s.
  33.      */
  34.     /**
  35.      * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
  36.      */
  37.     minWidth : 120,
  38.     /**
  39.      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
  40.      * for bottom-right shadow (defaults to "sides")
  41.      */
  42.     shadow : "sides",
  43.     /**
  44.      * @cfg {String} subMenuAlign The {@link Ext.Element#alignTo} anchor position value to use for submenus of
  45.      * this menu (defaults to "tl-tr?")
  46.      */
  47.     subMenuAlign : "tl-tr?",
  48.     /**
  49.      * @cfg {String} defaultAlign The default {@link Ext.Element#alignTo} anchor position value for this menu
  50.      * relative to its element of origin (defaults to "tl-bl?")
  51.      */
  52.     defaultAlign : "tl-bl?",
  53.     /**
  54.      * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
  55.      */
  56.     allowOtherMenus : false,
  57.     /**
  58.      * @cfg {Boolean} ignoreParentClicks True to ignore clicks on any item in this menu that is a parent item (displays
  59.      * a submenu) so that the submenu is not dismissed when clicking the parent item (defaults to false).
  60.      */
  61.     ignoreParentClicks : false,
  62.     /**
  63.      * @cfg {Boolean} enableScrolling True to allow the menu container to have scroller controls if the menu is too long (defaults to true).
  64.      */
  65.     enableScrolling: true,
  66.     /**
  67.      * @cfg {Number} maxHeight The maximum height of the menu. Only applies when enableScrolling is set to True (defaults to null).
  68.      */
  69.     maxHeight: null,
  70.     /**
  71.      * @cfg {Number} scrollIncrement The amount to scroll the menu. Only applies when enableScrolling is set to True (defaults to 24).
  72.      */
  73.     scrollIncrement: 24,
  74.     /**
  75.      * @cfg {Boolean} showSeparator True to show the icon separator. (defaults to true).
  76.      */
  77.     showSeparator: true,
  78.     /**
  79.      * @cfg {Array} defaultOffsets An array specifying the [x, y] offset in pixels by which to
  80.      * change the default Menu popup position after aligning according to the {@link #defaultAlign}
  81.      * configuration. Defaults to <tt>[0, 0]</tt>.
  82.      */
  83.     defaultOffsets : [0, 0],
  84.     /**
  85.      * @cfg {Boolean} floating
  86.      * May be specified as false to create a Menu which may be used as a child item of another Container
  87.      * instead of a free-floating {@link Ext.Layer Layer}. (defaults to true).
  88.      */
  89.     floating: true,         // Render as a Layer by default
  90.     // private
  91.     hidden: true,
  92.     layout: 'menu',
  93.     hideMode: 'offsets',    // Important for laying out Components
  94.     scrollerHeight: 8,
  95.     autoLayout: true,       // Provided for backwards compat
  96.     defaultType: 'menuitem',
  97.     initComponent: function(){
  98.         if(Ext.isArray(this.initialConfig)){
  99.             Ext.apply(this, {items:this.initialConfig});
  100.         }
  101.         this.addEvents(
  102.             /**
  103.              * @event click
  104.              * Fires when this menu is clicked (or when the enter key is pressed while it is active)
  105.              * @param {Ext.menu.Menu} this
  106.             * @param {Ext.menu.Item} menuItem The menu item that was clicked
  107.              * @param {Ext.EventObject} e
  108.              */
  109.             'click',
  110.             /**
  111.              * @event mouseover
  112.              * Fires when the mouse is hovering over this menu
  113.              * @param {Ext.menu.Menu} this
  114.              * @param {Ext.EventObject} e
  115.              * @param {Ext.menu.Item} menuItem The menu item that was clicked
  116.              */
  117.             'mouseover',
  118.             /**
  119.              * @event mouseout
  120.              * Fires when the mouse exits this menu
  121.              * @param {Ext.menu.Menu} this
  122.              * @param {Ext.EventObject} e
  123.              * @param {Ext.menu.Item} menuItem The menu item that was clicked
  124.              */
  125.             'mouseout',
  126.             /**
  127.              * @event itemclick
  128.              * Fires when a menu item contained in this menu is clicked
  129.              * @param {Ext.menu.BaseItem} baseItem The BaseItem that was clicked
  130.              * @param {Ext.EventObject} e
  131.              */
  132.             'itemclick'
  133.         );
  134.         Ext.menu.MenuMgr.register(this);
  135.         if(this.floating){
  136.             Ext.EventManager.onWindowResize(this.hide, this);
  137.         }else{
  138.             if(this.initialConfig.hidden !== false){
  139.                 this.hidden = false;
  140.             }
  141.             this.internalDefaults = {hideOnClick: false};
  142.         }
  143.         Ext.menu.Menu.superclass.initComponent.call(this);
  144.         if(this.autoLayout){
  145.             this.on({
  146.                 add: this.doLayout,
  147.                 remove: this.doLayout,
  148.                 scope: this
  149.             });
  150.         }
  151.     },
  152.     //private
  153.     getLayoutTarget : function() {
  154.         return this.ul;
  155.     },
  156.     // private
  157.     onRender : function(ct, position){
  158.         if(!ct){
  159.             ct = Ext.getBody();
  160.         }
  161.         var dh = {
  162.             id: this.getId(),
  163.             cls: 'x-menu ' + ((this.floating) ? 'x-menu-floating x-layer ' : '') + (this.cls || '') + (this.plain ? ' x-menu-plain' : '') + (this.showSeparator ? '' : ' x-menu-nosep'),
  164.             style: this.style,
  165.             cn: [
  166.                 {tag: 'a', cls: 'x-menu-focus', href: '#', onclick: 'return false;', tabIndex: '-1'},
  167.                 {tag: 'ul', cls: 'x-menu-list'}
  168.             ]
  169.         };
  170.         if(this.floating){
  171.             this.el = new Ext.Layer({
  172.                 shadow: this.shadow,
  173.                 dh: dh,
  174.                 constrain: false,
  175.                 parentEl: ct,
  176.                 zindex:15000
  177.             });
  178.         }else{
  179.             this.el = ct.createChild(dh);
  180.         }
  181.         Ext.menu.Menu.superclass.onRender.call(this, ct, position);
  182.         if(!this.keyNav){
  183.             this.keyNav = new Ext.menu.MenuNav(this);
  184.         }
  185.         // generic focus element
  186.         this.focusEl = this.el.child('a.x-menu-focus');
  187.         this.ul = this.el.child('ul.x-menu-list');
  188.         this.mon(this.ul, {
  189.             scope: this,
  190.             click: this.onClick,
  191.             mouseover: this.onMouseOver,
  192.             mouseout: this.onMouseOut
  193.         });
  194.         if(this.enableScrolling){
  195.             this.mon(this.el, {
  196.                 scope: this,
  197.                 delegate: '.x-menu-scroller',
  198.                 click: this.onScroll,
  199.                 mouseover: this.deactivateActive
  200.             });
  201.         }
  202.     },
  203.     // private
  204.     findTargetItem : function(e){
  205.         var t = e.getTarget(".x-menu-list-item", this.ul, true);
  206.         if(t && t.menuItemId){
  207.             return this.items.get(t.menuItemId);
  208.         }
  209.     },
  210.     // private
  211.     onClick : function(e){
  212.         var t = this.findTargetItem(e);
  213.         if(t){
  214.             if(t.isFormField){
  215.                 this.setActiveItem(t);
  216.             }else{
  217.                 if(t.menu && this.ignoreParentClicks){
  218.                     t.expandMenu();
  219.                     e.preventDefault();
  220.                 }else if(t.onClick){
  221.                     t.onClick(e);
  222.                     this.fireEvent("click", this, t, e);
  223.                 }
  224.             }
  225.         }
  226.     },
  227.     // private
  228.     setActiveItem : function(item, autoExpand){
  229.         if(item != this.activeItem){
  230.             this.deactivateActive();
  231.             if((this.activeItem = item).isFormField){
  232.                 item.focus();
  233.             }else{
  234.                 item.activate(autoExpand);
  235.             }
  236.         }else if(autoExpand){
  237.             item.expandMenu();
  238.         }
  239.     },
  240.     deactivateActive: function(){
  241.         var a = this.activeItem;
  242.         if(a){
  243.             if(a.isFormField){
  244.                 //Fields cannot deactivate, but Combos must collapse
  245.                 if(a.collapse){
  246.                     a.collapse();
  247.                 }
  248.             }else{
  249.                 a.deactivate();
  250.             }
  251.             delete this.activeItem;
  252.         }
  253.     },
  254.     // private
  255.     tryActivate : function(start, step){
  256.         var items = this.items;
  257.         for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
  258.             var item = items.get(i);
  259.             if(!item.disabled && (item.canActivate || item.isFormField)){
  260.                 this.setActiveItem(item, false);
  261.                 return item;
  262.             }
  263.         }
  264.         return false;
  265.     },
  266.     // private
  267.     onMouseOver : function(e){
  268.         var t = this.findTargetItem(e);
  269.         if(t){
  270.             if(t.canActivate && !t.disabled){
  271.                 this.setActiveItem(t, true);
  272.             }
  273.         }
  274.         this.over = true;
  275.         this.fireEvent("mouseover", this, e, t);
  276.     },
  277.     // private
  278.     onMouseOut : function(e){
  279.         var t = this.findTargetItem(e);
  280.         if(t){
  281.             if(t == this.activeItem && t.shouldDeactivate && t.shouldDeactivate(e)){
  282.                 this.activeItem.deactivate();
  283.                 delete this.activeItem;
  284.             }
  285.         }
  286.         this.over = false;
  287.         this.fireEvent("mouseout", this, e, t);
  288.     },
  289.     // private
  290.     onScroll: function(e, t){
  291.         if(e){
  292.             e.stopEvent();
  293.         }
  294.         var ul = this.ul.dom, top = Ext.fly(t).is('.x-menu-scroller-top');
  295.         ul.scrollTop += this.scrollIncrement * (top ? -1 : 1);
  296.         if(top ? ul.scrollTop <= 0 : ul.scrollTop + this.activeMax >= ul.scrollHeight){
  297.            this.onScrollerOut(null, t);
  298.         }
  299.     },
  300.     // private
  301.     onScrollerIn: function(e, t){
  302.         var ul = this.ul.dom, top = Ext.fly(t).is('.x-menu-scroller-top');
  303.         if(top ? ul.scrollTop > 0 : ul.scrollTop + this.activeMax < ul.scrollHeight){
  304.             Ext.fly(t).addClass(['x-menu-item-active', 'x-menu-scroller-active']);
  305.         }
  306.     },
  307.     // private
  308.     onScrollerOut: function(e, t){
  309.         Ext.fly(t).removeClass(['x-menu-item-active', 'x-menu-scroller-active']);
  310.     },
  311.     /**
  312.      * Displays this menu relative to another element
  313.      * @param {Mixed} element The element to align to
  314.      * @param {String} position (optional) The {@link Ext.Element#alignTo} anchor position to use in aligning to
  315.      * the element (defaults to this.defaultAlign)
  316.      * @param {Ext.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
  317.      */
  318.     show : function(el, pos, parentMenu){
  319.         if(this.floating){
  320.             this.parentMenu = parentMenu;
  321.             if(!this.el){
  322.                 this.render();
  323.                 this.doLayout(false, true);
  324.             }
  325.             if(this.fireEvent('beforeshow', this) !== false){
  326.                 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign, this.defaultOffsets), parentMenu, false);
  327.             }
  328.         }else{
  329.             Ext.menu.Menu.superclass.show.call(this);
  330.         }
  331.     },
  332.     /**
  333.      * Displays this menu at a specific xy position
  334.      * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
  335.      * @param {Ext.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
  336.      */
  337.     showAt : function(xy, parentMenu, /* private: */_e){
  338.         this.parentMenu = parentMenu;
  339.         if(!this.el){
  340.             this.render();
  341.         }
  342.         this.el.setXY(xy);
  343.         if(this.enableScrolling){
  344.             this.constrainScroll(xy[1]);
  345.         }
  346.         this.el.show();
  347.         Ext.menu.Menu.superclass.onShow.call(this);
  348.         if(Ext.isIE){
  349.             this.layout.doAutoSize();
  350.             if(!Ext.isIE8){
  351.                 this.el.repaint();
  352.             }
  353.         }
  354.         this.hidden = false;
  355.         this.focus();
  356.         this.fireEvent("show", this);
  357.     },
  358.     constrainScroll: function(y){
  359.         var max, full = this.ul.setHeight('auto').getHeight();
  360.         if(this.floating){
  361.             max = this.maxHeight ? this.maxHeight : Ext.fly(this.el.dom.parentNode).getViewSize().height - y;
  362.         }else{
  363.             max = this.getHeight();
  364.         }
  365.         if(full > max && max > 0){
  366.             this.activeMax = max - this.scrollerHeight * 2 - this.el.getFrameWidth('tb') - Ext.num(this.el.shadowOffset, 0);
  367.             this.ul.setHeight(this.activeMax);
  368.             this.createScrollers();
  369.             this.el.select('.x-menu-scroller').setDisplayed('');
  370.         }else{
  371.             this.ul.setHeight(full);
  372.             this.el.select('.x-menu-scroller').setDisplayed('none');
  373.         }
  374.         this.ul.dom.scrollTop = 0;
  375.     },
  376.     createScrollers: function(){
  377.         if(!this.scroller){
  378.             this.scroller = {
  379.                 pos: 0,
  380.                 top: this.el.insertFirst({
  381.                     tag: 'div',
  382.                     cls: 'x-menu-scroller x-menu-scroller-top',
  383.                     html: '&#160;'
  384.                 }),
  385.                 bottom: this.el.createChild({
  386.                     tag: 'div',
  387.                     cls: 'x-menu-scroller x-menu-scroller-bottom',
  388.                     html: '&#160;'
  389.                 })
  390.             };
  391.             this.scroller.top.hover(this.onScrollerIn, this.onScrollerOut, this);
  392.             this.scroller.topRepeater = new Ext.util.ClickRepeater(this.scroller.top, {
  393.                 listeners: {
  394.                     click: this.onScroll.createDelegate(this, [null, this.scroller.top], false)
  395.                 }
  396.             });
  397.             this.scroller.bottom.hover(this.onScrollerIn, this.onScrollerOut, this);
  398.             this.scroller.bottomRepeater = new Ext.util.ClickRepeater(this.scroller.bottom, {
  399.                 listeners: {
  400.                     click: this.onScroll.createDelegate(this, [null, this.scroller.bottom], false)
  401.                 }
  402.             });
  403.         }
  404.     },
  405.     onLayout: function(){
  406.         if(this.isVisible()){
  407.             if(this.enableScrolling){
  408.                 this.constrainScroll(this.el.getTop());
  409.             }
  410.             if(this.floating){
  411.                 this.el.sync();
  412.             }
  413.         }
  414.     },
  415.     focus : function(){
  416.         if(!this.hidden){
  417.             this.doFocus.defer(50, this);
  418.         }
  419.     },
  420.     doFocus : function(){
  421.         if(!this.hidden){
  422.             this.focusEl.focus();
  423.         }
  424.     },
  425.     /**
  426.      * Hides this menu and optionally all parent menus
  427.      * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
  428.      */
  429.     hide : function(deep){
  430.         this.deepHide = deep;
  431.         Ext.menu.Menu.superclass.hide.call(this);
  432.         delete this.deepHide;
  433.     },
  434.     // private
  435.     onHide: function(){
  436.         Ext.menu.Menu.superclass.onHide.call(this);
  437.         this.deactivateActive();
  438.         if(this.el && this.floating){
  439.             this.el.hide();
  440.         }
  441.         if(this.deepHide === true && this.parentMenu){
  442.             this.parentMenu.hide(true);
  443.         }
  444.     },
  445.     // private
  446.     lookupComponent: function(c){
  447.          if(Ext.isString(c)){
  448.             c = (c == 'separator' || c == '-') ? new Ext.menu.Separator() : new Ext.menu.TextItem(c);
  449.              this.applyDefaults(c);
  450.          }else{
  451.             if(Ext.isObject(c)){
  452.                 c = this.getMenuItem(c);
  453.             }else if(c.tagName || c.el){ // element. Wrap it.
  454.                 c = new Ext.BoxComponent({
  455.                     el: c
  456.                 });
  457.             }
  458.          }
  459.          return c;
  460.     },
  461.     applyDefaults : function(c){
  462.         if(!Ext.isString(c)){
  463.             c = Ext.menu.Menu.superclass.applyDefaults.call(this, c);
  464.             var d = this.internalDefaults;
  465.             if(d){
  466.                 if(c.events){
  467.                     Ext.applyIf(c.initialConfig, d);
  468.                     Ext.apply(c, d);
  469.                 }else{
  470.                     Ext.applyIf(c, d);
  471.                 }
  472.             }
  473.         }
  474.         return c;
  475.     },
  476.     // private
  477.     getMenuItem: function(config){
  478.        if(!config.isXType){
  479.             if(!config.xtype && Ext.isBoolean(config.checked)){
  480.                 return new Ext.menu.CheckItem(config)
  481.             }
  482.             return Ext.create(config, this.defaultType);
  483.         }
  484.         return config;
  485.     },
  486.     /**
  487.      * Adds a separator bar to the menu
  488.      * @return {Ext.menu.Item} The menu item that was added
  489.      */
  490.     addSeparator : function(){
  491.         return this.add(new Ext.menu.Separator());
  492.     },
  493.     /**
  494.      * Adds an {@link Ext.Element} object to the menu
  495.      * @param {Mixed} el The element or DOM node to add, or its id
  496.      * @return {Ext.menu.Item} The menu item that was added
  497.      */
  498.     addElement : function(el){
  499.         return this.add(new Ext.menu.BaseItem(el));
  500.     },
  501.     /**
  502.      * Adds an existing object based on {@link Ext.menu.BaseItem} to the menu
  503.      * @param {Ext.menu.Item} item The menu item to add
  504.      * @return {Ext.menu.Item} The menu item that was added
  505.      */
  506.     addItem : function(item){
  507.         return this.add(item);
  508.     },
  509.     /**
  510.      * Creates a new {@link Ext.menu.Item} based an the supplied config object and adds it to the menu
  511.      * @param {Object} config A MenuItem config object
  512.      * @return {Ext.menu.Item} The menu item that was added
  513.      */
  514.     addMenuItem : function(config){
  515.         return this.add(this.getMenuItem(config));
  516.     },
  517.     /**
  518.      * Creates a new {@link Ext.menu.TextItem} with the supplied text and adds it to the menu
  519.      * @param {String} text The text to display in the menu item
  520.      * @return {Ext.menu.Item} The menu item that was added
  521.      */
  522.     addText : function(text){
  523.         return this.add(new Ext.menu.TextItem(text));
  524.     },
  525.     //private
  526.     onDestroy : function(){
  527.         Ext.menu.Menu.superclass.onDestroy.call(this);
  528.         Ext.menu.MenuMgr.unregister(this);
  529.         Ext.EventManager.removeResizeListener(this.hide, this);
  530.         if(this.keyNav) {
  531.             this.keyNav.disable();
  532.         }
  533.         var s = this.scroller;
  534.         if(s){
  535.             Ext.destroy(s.topRepeater, s.bottomRepeater, s.top, s.bottom);
  536.         }
  537.     }
  538. });
  539. Ext.reg('menu', Ext.menu.Menu);
  540. // MenuNav is a private utility class used internally by the Menu
  541. Ext.menu.MenuNav = Ext.extend(Ext.KeyNav, function(){
  542.     function up(e, m){
  543.         if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
  544.             m.tryActivate(m.items.length-1, -1);
  545.         }
  546.     }
  547.     function down(e, m){
  548.         if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
  549.             m.tryActivate(0, 1);
  550.         }
  551.     }
  552.     return {
  553.         constructor: function(menu){
  554.             Ext.menu.MenuNav.superclass.constructor.call(this, menu.el);
  555.             this.scope = this.menu = menu;
  556.         },
  557.         doRelay : function(e, h){
  558.             var k = e.getKey();
  559. //          Keystrokes within a form Field (e.g.: down in a Combo) do not navigate. Allow only TAB
  560.             if (this.menu.activeItem && this.menu.activeItem.isFormField && k != e.TAB) {
  561.                 return false;
  562.             }
  563.             if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
  564.                 this.menu.tryActivate(0, 1);
  565.                 return false;
  566.             }
  567.             return h.call(this.scope || this, e, this.menu);
  568.         },
  569.         tab: function(e, m) {
  570.             e.stopEvent();
  571.             if (e.shiftKey) {
  572.                 up(e, m);
  573.             } else {
  574.                 down(e, m);
  575.             }
  576.         },
  577.         up : up,
  578.         down : down,
  579.         right : function(e, m){
  580.             if(m.activeItem){
  581.                 m.activeItem.expandMenu(true);
  582.             }
  583.         },
  584.         left : function(e, m){
  585.             m.hide();
  586.             if(m.parentMenu && m.parentMenu.activeItem){
  587.                 m.parentMenu.activeItem.activate();
  588.             }
  589.         },
  590.         enter : function(e, m){
  591.             if(m.activeItem){
  592.                 e.stopPropagation();
  593.                 m.activeItem.onClick(e);
  594.                 m.fireEvent("click", this, m.activeItem);
  595.                 return true;
  596.             }
  597.         }
  598.     };
  599. }());/**  * @class Ext.menu.MenuMgr  * Provides a common registry of all menu items on a page so that they can be easily accessed by id.  * @singleton  */ Ext.menu.MenuMgr = function(){    var menus, active, groups = {}, attached = false, lastShow = new Date();    // private - called when first menu is created    function init(){        menus = {};        active = new Ext.util.MixedCollection();        Ext.getDoc().addKeyListener(27, function(){            if(active.length > 0){                hideAll();            }        });    }    // private    function hideAll(){        if(active && active.length > 0){            var c = active.clone();            c.each(function(m){                m.hide();            });        }    }    // private    function onHide(m){        active.remove(m);        if(active.length < 1){            Ext.getDoc().un("mousedown", onMouseDown);            attached = false;        }    }    // private    function onShow(m){        var last = active.last();        lastShow = new Date();        active.add(m);        if(!attached){            Ext.getDoc().on("mousedown", onMouseDown);            attached = true;        }        if(m.parentMenu){           m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);           m.parentMenu.activeChild = m;        }else if(last && last.isVisible()){           m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);        }    }    // private    function onBeforeHide(m){        if(m.activeChild){            m.activeChild.hide();        }        if(m.autoHideTimer){            clearTimeout(m.autoHideTimer);            delete m.autoHideTimer;        }    }    // private    function onBeforeShow(m){        var pm = m.parentMenu;        if(!pm && !m.allowOtherMenus){            hideAll();        }else if(pm && pm.activeChild){            pm.activeChild.hide();        }    }    // private    function onMouseDown(e){        if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){            hideAll();        }    }    // private    function onBeforeCheck(mi, state){        if(state){            var g = groups[mi.group];            for(var i = 0, l = g.length; i < l; i++){                if(g[i] != mi){                    g[i].setChecked(false);                }            }        }    }    return {        /**         * Hides all menus that are currently visible         */        hideAll : function(){             hideAll();          },        // private        register : function(menu){            if(!menus){                init();            }            menus[menu.id] = menu;            menu.on("beforehide", onBeforeHide);            menu.on("hide", onHide);            menu.on("beforeshow", onBeforeShow);            menu.on("show", onShow);            var g = menu.group;            if(g && menu.events["checkchange"]){                if(!groups[g]){                    groups[g] = [];                }                groups[g].push(menu);                menu.on("checkchange", onCheck);            }        },         /**          * Returns a {@link Ext.menu.Menu} object          * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will          * be used to generate and return a new Menu instance.          * @return {Ext.menu.Menu} The specified menu, or null if none are found          */        get : function(menu){            if(typeof menu == "string"){ // menu id                if(!menus){  // not initialized, no menus to return                    return null;                }                return menus[menu];            }else if(menu.events){  // menu instance                return menu;            }else if(typeof menu.length == 'number'){ // array of menu items?                return new Ext.menu.Menu({items:menu});            }else{ // otherwise, must be a config                return Ext.create(menu, 'menu');            }        },        // private        unregister : function(menu){            delete menus[menu.id];            menu.un("beforehide", onBeforeHide);            menu.un("hide", onHide);            menu.un("beforeshow", onBeforeShow);            menu.un("show", onShow);            var g = menu.group;            if(g && menu.events["checkchange"]){                groups[g].remove(menu);                menu.un("checkchange", onCheck);            }        },        // private        registerCheckable : function(menuItem){            var g = menuItem.group;            if(g){                if(!groups[g]){                    groups[g] = [];                }                groups[g].push(menuItem);                menuItem.on("beforecheckchange", onBeforeCheck);            }        },        // private        unregisterCheckable : function(menuItem){            var g = menuItem.group;            if(g){                groups[g].remove(menuItem);                menuItem.un("beforecheckchange", onBeforeCheck);            }        },        getCheckedItem : function(groupId){            var g = groups[groupId];            if(g){                for(var i = 0, l = g.length; i < l; i++){                    if(g[i].checked){                        return g[i];                    }                }            }            return null;        },        setCheckedItem : function(groupId, itemId){            var g = groups[groupId];            if(g){                for(var i = 0, l = g.length; i < l; i++){                    if(g[i].id == itemId){                        g[i].setChecked(true);                    }                }            }            return null;        }    }; }(); /**  * @class Ext.menu.BaseItem  * @extends Ext.Component  * The base class for all items that render into menus.  BaseItem provides default rendering, activated state  * management and base configuration options shared by all menu components.  * @constructor  * Creates a new BaseItem  * @param {Object} config Configuration options  * @xtype menubaseitem  */ Ext.menu.BaseItem = function(config){     Ext.menu.BaseItem.superclass.constructor.call(this, config);     this.addEvents(         /**          * @event click          * Fires when this item is clicked          * @param {Ext.menu.BaseItem} this          * @param {Ext.EventObject} e          */         'click',         /**          * @event activate          * Fires when this item is activated          * @param {Ext.menu.BaseItem} this          */         'activate',         /**          * @event deactivate          * Fires when this item is deactivated          * @param {Ext.menu.BaseItem} this          */         'deactivate'     );     if(this.handler){         this.on("click", this.handler, this.scope);     } }; Ext.extend(Ext.menu.BaseItem, Ext.Component, {     /**      * @property parentMenu      * @type Ext.menu.Menu      * The parent Menu of this Item.      */     /**      * @cfg {Function} handler      * A function that will handle the click event of this menu item (optional).      * The handler is passed the following parameters:<div class="mdetail-params"><ul>      * <li><code>b</code> : Item<div class="sub-desc">This menu Item.</div></li>      * <li><code>e</code> : EventObject<div class="sub-desc">The click event.</div></li>      * </ul></div>      */     /**      * @cfg {Object} scope      * The scope (<tt><b>this</b></tt> reference) in which the handler function will be called.      */     /**      * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)      */     canActivate : false,     /**      * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")      */     activeClass : "x-menu-item-active",     /**      * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)      */     hideOnClick : true,     /**      * @cfg {Number} clickHideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)      */     clickHideDelay : 1,     // private     ctype : "Ext.menu.BaseItem",     // private     actionMode : "container",     // private     onRender : function(container, position){         Ext.menu.BaseItem.superclass.onRender.apply(this, arguments);         if(this.ownerCt && this.ownerCt instanceof Ext.menu.Menu){             this.parentMenu = this.ownerCt;         }else{             this.container.addClass('x-menu-list-item');             this.mon(this.el, 'click', this.onClick, this);             this.mon(this.el, 'mouseenter', this.activate, this);             this.mon(this.el, 'mouseleave', this.deactivate, this);         }     },     /**      * Sets the function that will handle click events for this item (equivalent to passing in the {@link #handler}      * config property).  If an existing handler is already registered, it will be unregistered for you.      * @param {Function} handler The function that should be called on click      * @param {Object} scope The scope that should be passed to the handler      */     setHandler : function(handler, scope){         if(this.handler){             this.un("click", this.handler, this.scope);         }         this.on("click", this.handler = handler, this.scope = scope);     },     // private     onClick : function(e){         if(!this.disabled && this.fireEvent("click", this, e) !== false                 && (this.parentMenu && this.parentMenu.fireEvent("itemclick", this, e) !== false)){             this.handleClick(e);         }else{             e.stopEvent();         }     },     // private     activate : function(){         if(this.disabled){             return false;         }         var li = this.container;         li.addClass(this.activeClass);         this.region = li.getRegion().adjust(2, 2, -2, -2);         this.fireEvent("activate", this);         return true;     },     // private     deactivate : function(){         this.container.removeClass(this.activeClass);         this.fireEvent("deactivate", this);     },     // private     shouldDeactivate : function(e){         return !this.region || !this.region.contains(e.getPoint());     },     // private     handleClick : function(e){         if(this.hideOnClick){             this.parentMenu.hide.defer(this.clickHideDelay, this.parentMenu, [true]);         }     },     // private. Do nothing     expandMenu : Ext.emptyFn,     // private. Do nothing     hideMenu : Ext.emptyFn }); Ext.reg('menubaseitem', Ext.menu.BaseItem);/**  * @class Ext.menu.TextItem  * @extends Ext.menu.BaseItem  * Adds a static text string to a menu, usually used as either a heading or group separator.  * @constructor  * Creates a new TextItem  * @param {Object/String} config If config is a string, it is used as the text to display, otherwise it  * is applied as a config object (and should contain a <tt>text</tt> property).  * @xtype menutextitem  */ Ext.menu.TextItem = function(cfg){     if(typeof cfg == 'string'){         cfg = {text: cfg}     }     Ext.menu.TextItem.superclass.constructor.call(this, cfg); }; Ext.extend(Ext.menu.TextItem, Ext.menu.BaseItem, {     /**      * @cfg {String} text The text to display for this item (defaults to '')      */     /**      * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)      */     hideOnClick : false,     /**      * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")      */     itemCls : "x-menu-text",     // private     onRender : function(){         var s = document.createElement("span");         s.className = this.itemCls;         s.innerHTML = this.text;         this.el = s;         Ext.menu.TextItem.superclass.onRender.apply(this, arguments);     } }); Ext.reg('menutextitem', Ext.menu.TextItem);/**  * @class Ext.menu.Separator  * @extends Ext.menu.BaseItem  * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will  * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.  * @constructor  * @param {Object} config Configuration options  * @xtype menuseparator  */ Ext.menu.Separator = function(config){     Ext.menu.Separator.superclass.constructor.call(this, config); }; Ext.extend(Ext.menu.Separator, Ext.menu.BaseItem, {     /**      * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")      */     itemCls : "x-menu-sep",     /**      * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)      */     hideOnClick : false,          /**       * @cfg {String} activeClass      * @hide       */     activeClass: '',     // private     onRender : function(li){         var s = document.createElement("span");         s.className = this.itemCls;         s.innerHTML = "&#160;";         this.el = s;         li.addClass("x-menu-sep-li");         Ext.menu.Separator.superclass.onRender.apply(this, arguments);     } }); Ext.reg('menuseparator', Ext.menu.Separator);/**
  600.  * @class Ext.menu.Item
  601.  * @extends Ext.menu.BaseItem
  602.  * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
  603.  * display items.  Item extends the base functionality of {@link Ext.menu.BaseItem} by adding menu-specific
  604.  * activation and click handling.
  605.  * @constructor
  606.  * Creates a new Item
  607.  * @param {Object} config Configuration options
  608.  * @xtype menuitem
  609.  */
  610. Ext.menu.Item = function(config){
  611.     Ext.menu.Item.superclass.constructor.call(this, config);
  612.     if(this.menu){
  613.         this.menu = Ext.menu.MenuMgr.get(this.menu);
  614.     }
  615. };
  616. Ext.extend(Ext.menu.Item, Ext.menu.BaseItem, {
  617.     /**
  618.      * @property menu
  619.      * @type Ext.menu.Menu
  620.      * The submenu associated with this Item if one was configured.
  621.      */
  622.     /**
  623.      * @cfg {Mixed} menu (optional) Either an instance of {@link Ext.menu.Menu} or the config object for an
  624.      * {@link Ext.menu.Menu} which acts as the submenu when this item is activated.
  625.      */
  626.     /**
  627.      * @cfg {String} icon The path to an icon to display in this item (defaults to Ext.BLANK_IMAGE_URL).  If
  628.      * icon is specified {@link #iconCls} should not be.
  629.      */
  630.     /**
  631.      * @cfg {String} iconCls A CSS class that specifies a background image that will be used as the icon for
  632.      * this item (defaults to '').  If iconCls is specified {@link #icon} should not be.
  633.      */
  634.     /**
  635.      * @cfg {String} text The text to display in this item (defaults to '').
  636.      */
  637.     /**
  638.      * @cfg {String} href The href attribute to use for the underlying anchor link (defaults to '#').
  639.      */
  640.     /**
  641.      * @cfg {String} hrefTarget The target attribute to use for the underlying anchor link (defaults to '').
  642.      */
  643.     /**
  644.      * @cfg {String} itemCls The default CSS class to use for menu items (defaults to 'x-menu-item')
  645.      */
  646.     itemCls : 'x-menu-item',
  647.     /**
  648.      * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
  649.      */
  650.     canActivate : true,
  651.     /**
  652.      * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
  653.      */
  654.     showDelay: 200,
  655.     // doc'd in BaseItem
  656.     hideDelay: 200,
  657.     // private
  658.     ctype: 'Ext.menu.Item',
  659.     // private
  660.     onRender : function(container, position){
  661.         if (!this.itemTpl) {
  662.             this.itemTpl = Ext.menu.Item.prototype.itemTpl = new Ext.XTemplate(
  663.                 '<a id="{id}" class="{cls}" hidefocus="true" unselectable="on" href="{href}"',
  664.                     '<tpl if="hrefTarget">',
  665.                         ' target="{hrefTarget}"',
  666.                     '</tpl>',
  667.                  '>',
  668.                      '<img src="{icon}" class="x-menu-item-icon {iconCls}"/>',
  669.                      '<span class="x-menu-item-text">{text}</span>',
  670.                  '</a>'
  671.              );
  672.         }
  673.         var a = this.getTemplateArgs();
  674.         this.el = position ? this.itemTpl.insertBefore(position, a, true) : this.itemTpl.append(container, a, true);
  675.         this.iconEl = this.el.child('img.x-menu-item-icon');
  676.         this.textEl = this.el.child('.x-menu-item-text');
  677.         Ext.menu.Item.superclass.onRender.call(this, container, position);
  678.     },
  679.     getTemplateArgs: function() {
  680.         return {
  681.             id: this.id,
  682.             cls: this.itemCls + (this.menu ?  ' x-menu-item-arrow' : '') + (this.cls ?  ' ' + this.cls : ''),
  683.             href: this.href || '#',
  684.             hrefTarget: this.hrefTarget,
  685.             icon: this.icon || Ext.BLANK_IMAGE_URL,
  686.             iconCls: this.iconCls || '',
  687.             text: this.itemText||this.text||'&#160;'
  688.         };
  689.     },
  690.     /**
  691.      * Sets the text to display in this menu item
  692.      * @param {String} text The text to display
  693.      */
  694.     setText : function(text){
  695.         this.text = text||'&#160;';
  696.         if(this.rendered){
  697.             this.textEl.update(this.text);
  698.             this.parentMenu.layout.doAutoSize();
  699.         }
  700.     },
  701.     /**
  702.      * Sets the CSS class to apply to the item's icon element
  703.      * @param {String} cls The CSS class to apply
  704.      */
  705.     setIconClass : function(cls){
  706.         var oldCls = this.iconCls;
  707.         this.iconCls = cls;
  708.         if(this.rendered){
  709.             this.iconEl.replaceClass(oldCls, this.iconCls);
  710.         }
  711.     },
  712.     
  713.     //private
  714.     beforeDestroy: function(){
  715.         if (this.menu){
  716.             this.menu.destroy();
  717.         }
  718.         Ext.menu.Item.superclass.beforeDestroy.call(this);
  719.     },
  720.     // private
  721.     handleClick : function(e){
  722.         if(!this.href){ // if no link defined, stop the event automatically
  723.             e.stopEvent();
  724.         }
  725.         Ext.menu.Item.superclass.handleClick.apply(this, arguments);
  726.     },
  727.     // private
  728.     activate : function(autoExpand){
  729.         if(Ext.menu.Item.superclass.activate.apply(this, arguments)){
  730.             this.focus();
  731.             if(autoExpand){
  732.                 this.expandMenu();
  733.             }
  734.         }
  735.         return true;
  736.     },
  737.     // private
  738.     shouldDeactivate : function(e){
  739.         if(Ext.menu.Item.superclass.shouldDeactivate.call(this, e)){
  740.             if(this.menu && this.menu.isVisible()){
  741.                 return !this.menu.getEl().getRegion().contains(e.getPoint());
  742.             }
  743.             return true;
  744.         }
  745.         return false;
  746.     },
  747.     // private
  748.     deactivate : function(){
  749.         Ext.menu.Item.superclass.deactivate.apply(this, arguments);
  750.         this.hideMenu();
  751.     },
  752.     // private
  753.     expandMenu : function(autoActivate){
  754.         if(!this.disabled && this.menu){
  755.             clearTimeout(this.hideTimer);
  756.             delete this.hideTimer;
  757.             if(!this.menu.isVisible() && !this.showTimer){
  758.                 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
  759.             }else if (this.menu.isVisible() && autoActivate){
  760.                 this.menu.tryActivate(0, 1);
  761.             }
  762.         }
  763.     },
  764.     // private
  765.     deferExpand : function(autoActivate){
  766.         delete this.showTimer;
  767.         this.menu.show(this.container, this.parentMenu.subMenuAlign || 'tl-tr?', this.parentMenu);
  768.         if(autoActivate){
  769.             this.menu.tryActivate(0, 1);
  770.         }
  771.     },
  772.     // private
  773.     hideMenu : function(){
  774.         clearTimeout(this.showTimer);
  775.         delete this.showTimer;
  776.         if(!this.hideTimer && this.menu && this.menu.isVisible()){
  777.             this.hideTimer = this.deferHide.defer(this.hideDelay, this);
  778.         }
  779.     },
  780.     // private
  781.     deferHide : function(){
  782.         delete this.hideTimer;
  783.         if(this.menu.over){
  784.             this.parentMenu.setActiveItem(this, false);
  785.         }else{
  786.             this.menu.hide();
  787.         }
  788.     }
  789. });
  790. Ext.reg('menuitem', Ext.menu.Item);/**  * @class Ext.menu.CheckItem  * @extends Ext.menu.Item  * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.  * @constructor  * Creates a new CheckItem  * @param {Object} config Configuration options  * @xtype menucheckitem  */ Ext.menu.CheckItem = function(config){     Ext.menu.CheckItem.superclass.constructor.call(this, config);     this.addEvents(         /**          * @event beforecheckchange          * Fires before the checked value is set, providing an opportunity to cancel if needed          * @param {Ext.menu.CheckItem} this          * @param {Boolean} checked The new checked value that will be set          */         "beforecheckchange" ,         /**          * @event checkchange          * Fires after the checked value has been set          * @param {Ext.menu.CheckItem} this          * @param {Boolean} checked The checked value that was set          */         "checkchange"     );     /**      * A function that handles the checkchange event.  The function is undefined by default, but if an implementation      * is provided, it will be called automatically when the checkchange event fires.      * @param {Ext.menu.CheckItem} this      * @param {Boolean} checked The checked value that was set      * @method checkHandler      */     if(this.checkHandler){         this.on('checkchange', this.checkHandler, this.scope);     }     Ext.menu.MenuMgr.registerCheckable(this); }; Ext.extend(Ext.menu.CheckItem, Ext.menu.Item, {     /**      * @cfg {String} group      * All check items with the same group name will automatically be grouped into a single-select      * radio button group (defaults to '')      */     /**      * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")      */     itemCls : "x-menu-item x-menu-check-item",     /**      * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")      */     groupClass : "x-menu-group-item",     /**      * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false).  Note that      * if this checkbox is part of a radio group (group = true) only the last item in the group that is      * initialized with checked = true will be rendered as checked.      */     checked: false,     // private     ctype: "Ext.menu.CheckItem",     // private     onRender : function(c){         Ext.menu.CheckItem.superclass.onRender.apply(this, arguments);         if(this.group){             this.el.addClass(this.groupClass);         }         if(this.checked){             this.checked = false;             this.setChecked(true, true);         }     },     // private     destroy : function(){         Ext.menu.MenuMgr.unregisterCheckable(this);         Ext.menu.CheckItem.superclass.destroy.apply(this, arguments);     },     /**      * Set the checked state of this item      * @param {Boolean} checked The new checked value      * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)      */     setChecked : function(state, suppressEvent){         if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){             if(this.container){                 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");             }             this.checked = state;             if(suppressEvent !== true){                 this.fireEvent("checkchange", this, state);             }         }     },     // private     handleClick : function(e){        if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item            this.setChecked(!this.checked);        }        Ext.menu.CheckItem.superclass.handleClick.apply(this, arguments);     } }); Ext.reg('menucheckitem', Ext.menu.CheckItem);/**
  791.  * @class Ext.menu.DateMenu
  792.  * @extends Ext.menu.Menu
  793.  * A menu containing a {@link Ext.DatePicker} Component.
  794.  * @xtype datemenu
  795.  */
  796.  Ext.menu.DateMenu = Ext.extend(Ext.menu.Menu, {
  797.     /** 
  798.      * @cfg {Boolean} enableScrolling
  799.      * @hide 
  800.      */
  801.     enableScrolling: false,
  802.     
  803.     /** 
  804.      * @cfg {Boolean} hideOnClick
  805.      * False to continue showing the menu after a date is selected, defaults to true.
  806.      */
  807.     hideOnClick: true,
  808.     
  809.     /** 
  810.      * @cfg {Number} maxHeight
  811.      * @hide 
  812.      */
  813.     /** 
  814.      * @cfg {Number} scrollIncrement
  815.      * @hide 
  816.      */
  817.     /**
  818.      * @property picker
  819.      * @type DatePicker
  820.      * The {@link Ext.DatePicker} instance for this DateMenu
  821.      */
  822.     cls: 'x-date-menu',
  823.     
  824.     /**
  825.      * @event click
  826.      * @hide
  827.      */
  828.     
  829.     /**
  830.      * @event itemclick
  831.      * @hide
  832.      */
  833.     initComponent: function(){
  834.         this.on('beforeshow', this.onBeforeShow, this);
  835.         if(this.strict = (Ext.isIE7 && Ext.isStrict)){
  836.             this.on('show', this.onShow, this, {single: true, delay: 20});
  837.         }
  838.         Ext.apply(this, {
  839.             plain: true,
  840.             showSeparator: false,
  841.             items: this.picker = new Ext.DatePicker(Ext.apply({
  842.                 internalRender: this.strict || !Ext.isIE,
  843.                 ctCls: 'x-menu-date-item'
  844.             }, this.initialConfig))
  845.         });
  846.         this.picker.purgeListeners();
  847.         Ext.menu.DateMenu.superclass.initComponent.call(this);
  848.         this.relayEvents(this.picker, ["select"]);
  849.         this.on('select', this.menuHide, this);
  850.         if(this.handler){
  851.             this.on('select', this.handler, this.scope || this);
  852.         }
  853.     },
  854.     menuHide: function() {
  855.         if(this.hideOnClick){
  856.             this.hide(true);
  857.         }
  858.     },
  859.     onBeforeShow: function(){
  860.         if(this.picker){
  861.             this.picker.hideMonthPicker(true);
  862.         }
  863.     },
  864.     onShow: function(){
  865.         var el = this.picker.getEl();
  866.         el.setWidth(el.getWidth()); //nasty hack for IE7 strict mode
  867.     }
  868.  });
  869.  Ext.reg('datemenu', Ext.menu.DateMenu);/**
  870.  * @class Ext.menu.ColorMenu
  871.  * @extends Ext.menu.Menu
  872.  * A menu containing a {@link Ext.ColorPalette} Component.
  873.  * @xtype colormenu
  874.  */
  875.  Ext.menu.ColorMenu = Ext.extend(Ext.menu.Menu, {
  876.     /** 
  877.      * @cfg {Boolean} enableScrolling
  878.      * @hide 
  879.      */
  880.     enableScrolling: false,
  881.     
  882.     /** 
  883.      * @cfg {Boolean} hideOnClick
  884.      * False to continue showing the menu after a color is selected, defaults to true.
  885.      */
  886.     hideOnClick: true,
  887.     
  888.     /** 
  889.      * @cfg {Number} maxHeight
  890.      * @hide 
  891.      */
  892.     /** 
  893.      * @cfg {Number} scrollIncrement
  894.      * @hide 
  895.      */
  896.     /**
  897.      * @property palette
  898.      * @type ColorPalette
  899.      * The {@link Ext.ColorPalette} instance for this ColorMenu
  900.      */
  901.     
  902.     
  903.     /**
  904.      * @event click
  905.      * @hide
  906.      */
  907.     
  908.     /**
  909.      * @event itemclick
  910.      * @hide
  911.      */
  912.     
  913.     initComponent: function(){
  914.         Ext.apply(this, {
  915.             plain: true,
  916.             showSeparator: false,
  917.             items: this.palette = new Ext.ColorPalette(this.initialConfig)
  918.         });
  919.         this.palette.purgeListeners();
  920.         Ext.menu.ColorMenu.superclass.initComponent.call(this);
  921.         this.relayEvents(this.palette, ['select']);
  922.         this.on('select', this.menuHide, this);
  923.         if(this.handler){
  924.             this.on('select', this.handler, this.scope || this)
  925.         }
  926.     },
  927.     menuHide: function(){
  928.         if(this.hideOnClick){
  929.             this.hide(true);
  930.         }
  931.     }
  932. });
  933. Ext.reg('colormenu', Ext.menu.ColorMenu);/**  * @class Ext.form.Field  * @extends Ext.BoxComponent  * Base class for form fields that provides default event handling, sizing, value handling and other functionality.  * @constructor  * Creates a new Field  * @param {Object} config Configuration options  * @xtype field  */ Ext.form.Field = Ext.extend(Ext.BoxComponent,  {     /**      * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password, file (defaults      * to "text"). The types "file" and "password" must be used to render those field types currently -- there are      * no separate Ext components for those. Note that if you use <tt>inputType:'file'</tt>, {@link #emptyText}      * is not supported and should be avoided.      */     /**      * @cfg {Number} tabIndex The tabIndex for this field. Note this only applies to fields that are rendered,      * not those which are built via applyTo (defaults to undefined).      */     /**      * @cfg {Mixed} value A value to initialize this field with (defaults to undefined).      */     /**      * @cfg {String} name The field's HTML name attribute (defaults to "").      * <b>Note</b>: this property must be set if this field is to be automatically included with      * {@link Ext.form.BasicForm#submit form submit()}.      */     /**      * @cfg {String} cls A custom CSS class to apply to the field's underlying element (defaults to "").      */     /**      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")      */     invalidClass : "x-form-invalid",     /**      * @cfg {String} invalidText The error text to use when marking a field invalid and no message is provided      * (defaults to "The value in this field is invalid")      */     invalidText : "The value in this field is invalid",     /**      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")      */     focusClass : "x-form-focus",     /**      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable       automatic validation (defaults to "keyup").      */     validationEvent : "keyup",     /**      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).      */     validateOnBlur : true,     /**      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation      * is initiated (defaults to 250)      */     validationDelay : 250,     /**      * @cfg {String/Object} autoCreate <p>A {@link Ext.DomHelper DomHelper} element spec, or true for a default      * element spec. Used to create the {@link Ext.Component#getEl Element} which will encapsulate this Component.      * See <tt>{@link Ext.Component#autoEl autoEl}</tt> for details.  Defaults to:</p>      * <pre><code>{tag: "input", type: "text", size: "20", autocomplete: "off"}</code></pre>      */     defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},     /**      * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")      */     fieldClass : "x-form-field",     /**      * @cfg {String} msgTarget The location where error text should display.  Should be one of the following values      * (defaults to 'qtip'):      *<pre> Value         Description -----------   ---------------------------------------------------------------------- qtip          Display a quick tip when the user hovers over the field title         Display a default browser title attribute popup under         Add a block div beneath the field containing the error text side          Add an error icon to the right of the field with a popup on hover [element id]  Add the error text directly to the innerHTML of the specified element </pre>      */     msgTarget : 'qtip',     /**      * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field      * (defaults to 'normal').      */     msgFx : 'normal',     /**      * @cfg {Boolean} readOnly <tt>true</tt> to mark the field as readOnly in HTML      * (defaults to <tt>false</tt>).      * <br><p><b>Note</b>: this only sets the element's readOnly DOM attribute.      * Setting <code>readOnly=true</code>, for example, will not disable triggering a      * ComboBox or DateField; it gives you the option of forcing the user to choose      * via the trigger without typing in the text box. To hide the trigger use      * <code>{@link Ext.form.TriggerField#hideTrigger hideTrigger}</code>.</p>      */     readOnly : false,     /**      * @cfg {Boolean} disabled True to disable the field (defaults to false).      * <p>Be aware that conformant with the <a href="http://www.w3.org/TR/html401/interact/forms.html#h-17.12.1">HTML specification</a>,      * disabled Fields will not be {@link Ext.form.BasicForm#submit submitted}.</p>      */     disabled : false,     // private     isFormField : true,     // private     hasFocus : false,     // private     initComponent : function(){         Ext.form.Field.superclass.initComponent.call(this);         this.addEvents(             /**              * @event focus              * Fires when this field receives input focus.              * @param {Ext.form.Field} this              */             'focus',             /**              * @event blur              * Fires when this field loses input focus.              * @param {Ext.form.Field} this              */             'blur',             /**              * @event specialkey              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.              * To handle other keys see {@link Ext.Panel#keys} or {@link Ext.KeyMap}.              * You can check {@link Ext.EventObject#getKey} to determine which key was pressed.              * For example: <pre><code> var form = new Ext.form.FormPanel({     ...     items: [{             fieldLabel: 'Field 1',             name: 'field1',             allowBlank: false         },{             fieldLabel: 'Field 2',             name: 'field2',             listeners: {                 specialkey: function(field, e){                     // e.HOME, e.END, e.PAGE_UP, e.PAGE_DOWN,                     // e.TAB, e.ESC, arrow keys: e.LEFT, e.RIGHT, e.UP, e.DOWN                     if (e.{@link Ext.EventObject#getKey getKey()} == e.ENTER) {                         var form = field.ownerCt.getForm();                         form.submit();                     }                 }             }         }     ],     ... });              * </code></pre>              * @param {Ext.form.Field} this              * @param {Ext.EventObject} e The event object              */             'specialkey',             /**              * @event change              * Fires just before the field blurs if the field value has changed.              * @param {Ext.form.Field} this              * @param {Mixed} newValue The new value              * @param {Mixed} oldValue The original value              */             'change',             /**              * @event invalid              * Fires after the field has been marked as invalid.              * @param {Ext.form.Field} this              * @param {String} msg The validation message              */             'invalid',             /**              * @event valid              * Fires after the field has been validated with no errors.              * @param {Ext.form.Field} this              */             'valid'         );     },     /**      * Returns the {@link Ext.form.Field#name name} or {@link Ext.form.ComboBox#hiddenName hiddenName}      * attribute of the field if available.      * @return {String} name The field {@link Ext.form.Field#name name} or {@link Ext.form.ComboBox#hiddenName hiddenName}        */     getName: function(){         return this.rendered && this.el.dom.name ? this.el.dom.name : this.name || this.id || '';     },     // private     onRender : function(ct, position){         if(!this.el){             var cfg = this.getAutoCreate();             if(!cfg.name){                 cfg.name = this.name || this.id;             }             if(this.inputType){                 cfg.type = this.inputType;             }             this.autoEl = cfg;         }         Ext.form.Field.superclass.onRender.call(this, ct, position);                  var type = this.el.dom.type;         if(type){             if(type == 'password'){                 type = 'text';             }             this.el.addClass('x-form-'+type);         }         if(this.readOnly){             this.el.dom.readOnly = true;         }         if(this.tabIndex !== undefined){             this.el.dom.setAttribute('tabIndex', this.tabIndex);         }         this.el.addClass([this.fieldClass, this.cls]);     },     // private     getItemCt : function(){         return this.el.up('.x-form-item', 4);     },     // private     initValue : function(){         if(this.value !== undefined){             this.setValue(this.value);         }else if(!Ext.isEmpty(this.el.dom.value) && this.el.dom.value != this.emptyText){             this.setValue(this.el.dom.value);         }         /**          * The original value of the field as configured in the {@link #value} configuration, or          * as loaded by the last form load operation if the form's {@link Ext.form.BasicForm#trackResetOnLoad trackResetOnLoad}          * setting is <code>true</code>.          * @type mixed          * @property originalValue          */         this.originalValue = this.getValue();     },     /**      * <p>Returns true if the value of this Field has been changed from its original value.      * Will return false if the field is disabled or has not been rendered yet.</p>      * <p>Note that if the owning {@link Ext.form.BasicForm form} was configured with      * {@link Ext.form.BasicForm}.{@link Ext.form.BasicForm#trackResetOnLoad trackResetOnLoad}      * then the <i>original value</i> is updated when the values are loaded by      * {@link Ext.form.BasicForm}.{@link Ext.form.BasicForm#setValues setValues}.</p>      * @return {Boolean} True if this field has been changed from its original value (and      * is not disabled), false otherwise.      */     isDirty : function() {         if(this.disabled || !this.rendered) {             return false;         }         return String(this.getValue()) !== String(this.originalValue);     },     // private     afterRender : function(){         Ext.form.Field.superclass.afterRender.call(this);         this.initEvents();         this.initValue();     },     // private     fireKey : function(e){         if(e.isSpecialKey()){             this.fireEvent("specialkey", this, e);         }     },     /**      * Resets the current field value to the originally loaded value and clears any validation messages.      * See {@link Ext.form.BasicForm}.{@link Ext.form.BasicForm#trackResetOnLoad trackResetOnLoad}      */     reset : function(){         this.setValue(this.originalValue);         this.clearInvalid();     },     // private     initEvents : function(){         this.mon(this.el, Ext.EventManager.useKeydown ? "keydown" : "keypress", this.fireKey,  this);         this.mon(this.el, 'focus', this.onFocus, this);         // fix weird FF/Win editor issue when changing OS window focus         var o = this.inEditor && Ext.isWindows && Ext.isGecko ? {buffer:10} : null;         this.mon(this.el, 'blur', this.onBlur, this, o);     },     // private     onFocus : function(){         if(this.focusClass){             this.el.addClass(this.focusClass);         }         if(!this.hasFocus){             this.hasFocus = true;             this.startValue = this.getValue();             this.fireEvent("focus", this);         }     },     // private     beforeBlur : Ext.emptyFn,     // private     onBlur : function(){         this.beforeBlur();         if(this.focusClass){             this.el.removeClass(this.focusClass);         }         this.hasFocus = false;         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){             this.validate();         }         var v = this.getValue();         if(String(v) !== String(this.startValue)){             this.fireEvent('change', this, v, this.startValue);         }         this.fireEvent("blur", this);     },     /**      * Returns whether or not the field value is currently valid      * @param {Boolean} preventMark True to disable marking the field invalid      * @return {Boolean} True if the value is valid, else false      */     isValid : function(preventMark){         if(this.disabled){             return true;         }         var restore = this.preventMark;         this.preventMark = preventMark === true;         var v = this.validateValue(this.processValue(this.getRawValue()));         this.preventMark = restore;         return v;     },     /**      * Validates the field value      * @return {Boolean} True if the value is valid, else false      */     validate : function(){         if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){             this.clearInvalid();             return true;         }         return false;     },     // protected - should be overridden by subclasses if necessary to prepare raw values for validation     processValue : function(value){         return value;     },     // private     // Subclasses should provide the validation implementation by overriding this     validateValue : function(value){         return true;     },     /**      * Mark this field as invalid, using {@link #msgTarget} to determine how to display the error and      * applying {@link #invalidClass} to the field's element.      * @param {String} msg (optional) The validation message (defaults to {@link #invalidText})      */     markInvalid : function(msg){         if(!this.rendered || this.preventMark){ // not rendered             return;         }         msg = msg || this.invalidText;         var mt = this.getMessageHandler();         if(mt){             mt.mark(this, msg);         }else if(this.msgTarget){             this.el.addClass(this.invalidClass);             var t = Ext.getDom(this.msgTarget);             if(t){                 t.innerHTML = msg;                 t.style.display = this.msgDisplay;             }         }         this.fireEvent('invalid', this, msg);     },     /**      * Clear any invalid styles/messages for this field      */     clearInvalid : function(){         if(!this.rendered || this.preventMark){ // not rendered             return;         }         this.el.removeClass(this.invalidClass);         var mt = this.getMessageHandler();         if(mt){             mt.clear(this);         }else if(this.msgTarget){             this.el.removeClass(this.invalidClass);             var t = Ext.getDom(this.msgTarget);             if(t){                 t.innerHTML = '';                 t.style.display = 'none';             }         }         this.fireEvent('valid', this);     },     // private     getMessageHandler : function(){         return Ext.form.MessageTargets[this.msgTarget];     },     // private     getErrorCt : function(){         return this.el.findParent('.x-form-element', 5, true) || // use form element wrap if available             this.el.findParent('.x-form-field-wrap', 5, true);   // else direct field wrap     },     // private     alignErrorIcon : function(){         this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);     },     /**      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.      * @return {Mixed} value The field value      */     getRawValue : function(){         var v = this.rendered ? this.el.getValue() : Ext.value(this.value, '');         if(v === this.emptyText){             v = '';         }         return v;     },     /**      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.      * @return {Mixed} value The field value      */     getValue : function(){         if(!this.rendered) {             return this.value;         }         var v = this.el.getValue();         if(v === this.emptyText || v === undefined){             v = '';         }         return v;     },     /**      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.      * @param {Mixed} value The value to set      * @return {Mixed} value The field value that is set      */     setRawValue : function(v){         return (this.el.dom.value = (Ext.isEmpty(v) ? '' : v));     },     /**      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.      * @param {Mixed} value The value to set      * @return {Ext.form.Field} this      */     setValue : function(v){         this.value = v;         if(this.rendered){             this.el.dom.value = (Ext.isEmpty(v) ? '' : v);             this.validate();         }         return this;     },     // private, does not work for all fields     append : function(v){          this.setValue([this.getValue(), v].join(''));     },     // private     adjustSize : function(w, h){         var s = Ext.form.Field.superclass.adjustSize.call(this, w, h);         s.width = this.adjustWidth(this.el.dom.tagName, s.width);         if(this.offsetCt){             var ct = this.getItemCt();             s.width -= ct.getFrameWidth('lr');             s.height -= ct.getFrameWidth('tb');         }         return s;     },     // private     adjustWidth : function(tag, w){         if(typeof w == 'number' && (Ext.isIE && (Ext.isIE6 || !Ext.isStrict)) && /input|textarea/i.test(tag) && !this.inEditor){             return w - 3;         }         return w;     }     /**      * @cfg {Boolean} autoWidth @hide      */     /**      * @cfg {Boolean} autoHeight @hide      */     /**      * @cfg {String} autoEl @hide      */ }); Ext.form.MessageTargets = {     'qtip' : {         mark: function(field, msg){             field.el.addClass(field.invalidClass);             field.el.dom.qtip = msg;             field.el.dom.qclass = 'x-form-invalid-tip';             if(Ext.QuickTips){ // fix for floating editors interacting with DND                 Ext.QuickTips.enable();             }         },         clear: function(field){             field.el.removeClass(field.invalidClass);             field.el.dom.qtip = '';         }     },     'title' : {         mark: function(field, msg){             field.el.addClass(field.invalidClass);             field.el.dom.title = msg;         },         clear: function(field){             field.el.dom.title = '';         }     },     'under' : {         mark: function(field, msg){             field.el.addClass(field.invalidClass);             if(!field.errorEl){                 var elp = field.getErrorCt();                 if(!elp){ // field has no container el                     field.el.dom.title = msg;                     return;                 }                 field.errorEl = elp.createChild({cls:'x-form-invalid-msg'});                 field.errorEl.setWidth(elp.getWidth(true)-20);             }             field.errorEl.update(msg);             Ext.form.Field.msgFx[field.msgFx].show(field.errorEl, field);         },         clear: function(field){             field.el.removeClass(field.invalidClass);             if(field.errorEl){                 Ext.form.Field.msgFx[field.msgFx].hide(field.errorEl, field);             }else{                 field.el.dom.title = '';             }         }     },     'side' : {         mark: function(field, msg){             field.el.addClass(field.invalidClass);             if(!field.errorIcon){                 var elp = field.getErrorCt();                 if(!elp){ // field has no container el                     field.el.dom.title = msg;                     return;                 }                 field.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});             }             field.alignErrorIcon();             field.errorIcon.dom.qtip = msg;             field.errorIcon.dom.qclass = 'x-form-invalid-tip';             field.errorIcon.show();             field.on('resize', field.alignErrorIcon, field);         },         clear: function(field){             field.el.removeClass(field.invalidClass);             if(field.errorIcon){                 field.errorIcon.dom.qtip = '';                 field.errorIcon.hide();                 field.un('resize', field.alignErrorIcon, field);             }else{                 field.el.dom.title = '';             }         }     } }; // anything other than normal should be considered experimental Ext.form.Field.msgFx = {     normal : {         show: function(msgEl, f){             msgEl.setDisplayed('block');         },         hide : function(msgEl, f){             msgEl.setDisplayed(false).update('');         }     },     slide : {         show: function(msgEl, f){             msgEl.slideIn('t', {stopFx:true});         },         hide : function(msgEl, f){             msgEl.slideOut('t', {stopFx:true,useDisplay:true});         }     },     slideRight : {         show: function(msgEl, f){             msgEl.fixDisplay();             msgEl.alignTo(f.el, 'tl-tr');             msgEl.slideIn('l', {stopFx:true});         },         hide : function(msgEl, f){             msgEl.slideOut('l', {stopFx:true,useDisplay:true});         }     } }; Ext.reg('field', Ext.form.Field); /**  * @class Ext.form.TextField  * @extends Ext.form.Field  * <p>Basic text field.  Can be used as a direct replacement for traditional text inputs,  * or as the base class for more sophisticated input controls (like {@link Ext.form.TextArea}  * and {@link Ext.form.ComboBox}).</p>  * <p><b><u>Validation</u></b></p>  * <p>Field validation is processed in a particular order.  If validation fails at any particular  * step the validation routine halts.</p>  * <div class="mdetail-params"><ul>  * <li><b>1. Field specific validator</b>  * <div class="sub-desc">  * <p>If a field is configured with a <code>{@link Ext.form.TextField#validator validator}</code> function,  * it will be passed the current field value.  The <code>{@link Ext.form.TextField#validator validator}</code>  * function is expected to return boolean <tt>true</tt> if the value is valid or return a string to  * represent the invalid message if invalid.</p>  * </div></li>  * <li><b>2. Built in Validation</b>  * <div class="sub-desc">  * <p>Basic validation is affected with the following configuration properties:</p>  * <pre>  * <u>Validation</u>    <u>Invalid Message</u>  * <code>{@link Ext.form.TextField#allowBlank allowBlank}    {@link Ext.form.TextField#emptyText emptyText}</code>  * <code>{@link Ext.form.TextField#minLength minLength}     {@link Ext.form.TextField#minLengthText minLengthText}</code>  * <code>{@link Ext.form.TextField#maxLength maxLength}     {@link Ext.form.TextField#maxLengthText maxLengthText}</code>  * </pre>  * </div></li>  * <li><b>3. Preconfigured Validation Types (VTypes)</b>  * <div class="sub-desc">  * <p>Using VTypes offers a convenient way to reuse validation. If a field is configured with a  * <code>{@link Ext.form.TextField#vtype vtype}</code>, the corresponding {@link Ext.form.VTypes VTypes}  * validation function will be used for validation.  If invalid, either the field's  * <code>{@link Ext.form.TextField#vtypeText vtypeText}</code> or the VTypes vtype Text property will be  * used for the invalid message.  Keystrokes on the field will be filtered according to the VTypes  * vtype Mask property.</p>  * </div></li>  * <li><b>4. Field specific regex test</b>  * <div class="sub-desc">  * <p>Each field may also specify a <code>{@link Ext.form.TextField#regex regex}</code> test.  * The invalid message for this test is configured with  * <code>{@link Ext.form.TextField#regexText regexText}</code>.</p>  * </div></li>  * <li><b>Alter Validation Behavior</b>  * <div class="sub-desc">  * <p>Validation behavior for each field can be configured:</p><ul>  * <li><code>{@link Ext.form.TextField#invalidText invalidText}</code> : the default validation message to  * show if any validation step above does not provide a message when invalid</li>  * <li><code>{@link Ext.form.TextField#maskRe maskRe}</code> : filter out keystrokes before any validation occurs</li>  * <li><code>{@link Ext.form.TextField#stripCharsRe stripCharsRe}</code> : filter characters after being typed in,  * but before being validated</li>  * <li><code>{@link Ext.form.Field#invalidClass invalidClass}</code> : alternate style when invalid</li>  * <li><code>{@link Ext.form.Field#validateOnBlur validateOnBlur}</code>,  * <code>{@link Ext.form.Field#validationDelay validationDelay}</code>, and  * <code>{@link Ext.form.Field#validationEvent validationEvent}</code> : modify how/when validation is triggered</li>  * </ul>  * </div></li>  * </ul></div>  * @constructor  * Creates a new TextField  * @param {Object} config Configuration options  * @xtype textfield  */ Ext.form.TextField = Ext.extend(Ext.form.Field,  {     /**      * @cfg {String} vtypeText A custom error message to display in place of the default message provided      * for the <b><code>{@link #vtype}</code></b> currently set for this field (defaults to <tt>''</tt>).  <b>Note</b>:      * only applies if <b><code>{@link #vtype}</code></b> is set, else ignored.      */     /**      * @cfg {RegExp} stripCharsRe A JavaScript RegExp object used to strip unwanted content from the value      * before validation (defaults to <tt>null</tt>).      */     /**      * @cfg {Boolean} grow <tt>true</tt> if this field should automatically grow and shrink to its content      * (defaults to <tt>false</tt>)      */     grow : false,     /**      * @cfg {Number} growMin The minimum width to allow when <code><b>{@link #grow}</b> = true</code> (defaults      * to <tt>30</tt>)      */     growMin : 30,     /**      * @cfg {Number} growMax The maximum width to allow when <code><b>{@link #grow}</b> = true</code> (defaults      * to <tt>800</tt>)      */     growMax : 800,     /**      * @cfg {String} vtype A validation type name as defined in {@link Ext.form.VTypes} (defaults to <tt>null</tt>)      */     vtype : null,     /**      * @cfg {RegExp} maskRe An input mask regular expression that will be used to filter keystrokes that do      * not match (defaults to <tt>null</tt>)      */     maskRe : null,     /**      * @cfg {Boolean} disableKeyFilter Specify <tt>true</tt> to disable input keystroke filtering (defaults      * to <tt>false</tt>)      */     disableKeyFilter : false,     /**      * @cfg {Boolean} allowBlank Specify <tt>false</tt> to validate that the value's length is > 0 (defaults to      * <tt>true</tt>)      */     allowBlank : true,     /**      * @cfg {Number} minLength Minimum input field length required (defaults to <tt>0</tt>)      */     minLength : 0,     /**      * @cfg {Number} maxLength Maximum input field length allowed by validation (defaults to Number.MAX_VALUE).      * This behavior is intended to provide instant feedback to the user by improving usability to allow pasting      * and editing or overtyping and back tracking. To restrict the maximum number of characters that can be      * entered into the field use <tt><b>{@link Ext.form.Field#autoCreate autoCreate}</b></tt> to add      * any attributes you want to a field, for example:<pre><code> var myField = new Ext.form.NumberField({     id: 'mobile',     anchor:'90%',     fieldLabel: 'Mobile',     maxLength: 16, // for validation     autoCreate: {tag: 'input', type: 'text', size: '20', autocomplete: 'off', maxlength: '10'} }); </code></pre>      */     maxLength : Number.MAX_VALUE,     /**      * @cfg {String} minLengthText Error text to display if the <b><tt>{@link #minLength minimum length}</tt></b>      * validation fails (defaults to <tt>'The minimum length for this field is {minLength}'</tt>)      */     minLengthText : 'The minimum length for this field is {0}',     /**      * @cfg {String} maxLengthText Error text to display if the <b><tt>{@link #maxLength maximum length}</tt></b>      * validation fails (defaults to <tt>'The maximum length for this field is {maxLength}'</tt>)      */     maxLengthText : 'The maximum length for this field is {0}',     /**      * @cfg {Boolean} selectOnFocus <tt>true</tt> to automatically select any existing field text when the field      * receives input focus (defaults to <tt>false</tt>)      */     selectOnFocus : false,     /**      * @cfg {String} blankText The error text to display if the <b><tt>{@link #allowBlank}</tt></b> validation      * fails (defaults to <tt>'This field is required'</tt>)      */     blankText : 'This field is required',     /**      * @cfg {Function} validator A custom validation function to be called during field validation      * (defaults to <tt>null</tt>). If specified, this function will be called first, allowing the      * developer to override the default validation process. This function will be passed the current      * field value and expected to return boolean <tt>true</tt> if the value is valid or a string      * error message if invalid.      */     validator : null,     /**      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation      * (defaults to <tt>null</tt>). If the test fails, the field will be marked invalid using      * <b><tt>{@link #regexText}</tt></b>.      */     regex : null,     /**      * @cfg {String} regexText The error text to display if <b><tt>{@link #regex}</tt></b> is used and the      * test fails during validation (defaults to <tt>''</tt>)      */     regexText : '',     /**      * @cfg {String} emptyText The default text to place into an empty field (defaults to <tt>null</tt>).      * <b>Note</b>: that this value will be submitted to the server if this field is enabled and configured      * with a {@link #name}.      */     emptyText : null,     /**      * @cfg {String} emptyClass The CSS class to apply to an empty field to style the <b><tt>{@link #emptyText}</tt></b>      * (defaults to <tt>'x-form-empty-field'</tt>).  This class is automatically added and removed as needed      * depending on the current field value.      */     emptyClass : 'x-form-empty-field',     /**      * @cfg {Boolean} enableKeyEvents <tt>true</tt> to enable the proxying of key events for the HTML input      * field (defaults to <tt>false</tt>)      */     initComponent : function(){         Ext.form.TextField.superclass.initComponent.call(this);         this.addEvents(             /**              * @event autosize              * Fires when the <tt><b>{@link #autoSize}</b></tt> function is triggered. The field may or              * may not have actually changed size according to the default logic, but this event provides              * a hook for the developer to apply additional logic at runtime to resize the field if needed.              * @param {Ext.form.Field} this This text field              * @param {Number} width The new field width              */             'autosize',             /**              * @event keydown              * Keydown input field event. This event only fires if <tt><b>{@link #enableKeyEvents}</b></tt>              * is set to true.              * @param {Ext.form.TextField} this This text field              * @param {Ext.EventObject} e              */             'keydown',             /**              * @event keyup              * Keyup input field event. This event only fires if <tt><b>{@link #enableKeyEvents}</b></tt>              * is set to true.              * @param {Ext.form.TextField} this This text field              * @param {Ext.EventObject} e              */             'keyup',             /**              * @event keypress              * Keypress input field event. This event only fires if <tt><b>{@link #enableKeyEvents}</b></tt>              * is set to true.              * @param {Ext.form.TextField} this This text field              * @param {Ext.EventObject} e              */             'keypress'         );     },     // private     initEvents : function(){         Ext.form.TextField.superclass.initEvents.call(this);         if(this.validationEvent == 'keyup'){             this.validationTask = new Ext.util.DelayedTask(this.validate, this);             this.mon(this.el, 'keyup', this.filterValidation, this);         }         else if(this.validationEvent !== false){          this.mon(this.el, this.validationEvent, this.validate, this, {buffer: this.validationDelay});         }         if(this.selectOnFocus || this.emptyText){             this.on('focus', this.preFocus, this);                          this.mon(this.el, 'mousedown', function(){                 if(!this.hasFocus){                     this.el.on('mouseup', function(e){                         e.preventDefault();                     }, this, {single:true});                 }             }, this);                          if(this.emptyText){                 this.on('blur', this.postBlur, this);                 this.applyEmptyText();             }         }         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Ext.form.VTypes[this.vtype+'Mask']))){          this.mon(this.el, 'keypress', this.filterKeys, this);         }         if(this.grow){          this.mon(this.el, 'keyup', this.onKeyUpBuffered, this, {buffer: 50}); this.mon(this.el, 'click', this.autoSize, this);         }         if(this.enableKeyEvents){          this.mon(this.el, 'keyup', this.onKeyUp, this);          this.mon(this.el, 'keydown', this.onKeyDown, this);          this.mon(this.el, 'keypress', this.onKeyPress, this);         }     },     processValue : function(value){         if(this.stripCharsRe){             var newValue = value.replace(this.stripCharsRe, '');             if(newValue !== value){                 this.setRawValue(newValue);                 return newValue;             }         }         return value;     },     filterValidation : function(e){         if(!e.isNavKeyPress()){             this.validationTask.delay(this.validationDelay);         }     },          //private     onDisable: function(){         Ext.form.TextField.superclass.onDisable.call(this);         if(Ext.isIE){             this.el.dom.unselectable = 'on';         }     },          //private     onEnable: function(){         Ext.form.TextField.superclass.onEnable.call(this);         if(Ext.isIE){             this.el.dom.unselectable = '';         }     },     // private     onKeyUpBuffered : function(e){         if(!e.isNavKeyPress()){             this.autoSize();         }     },     // private     onKeyUp : function(e){         this.fireEvent('keyup', this, e);     },     // private     onKeyDown : function(e){         this.fireEvent('keydown', this, e);     },     // private     onKeyPress : function(e){         this.fireEvent('keypress', this, e);     },     /**      * Resets the current field value to the originally-loaded value and clears any validation messages.      * Also adds <tt><b>{@link #emptyText}</b></tt> and <tt><b>{@link #emptyClass}</b></tt> if the      * original value was blank.      */     reset : function(){         Ext.form.TextField.superclass.reset.call(this);         this.applyEmptyText();     },     applyEmptyText : function(){         if(this.rendered && this.emptyText && this.getRawValue().length < 1 && !this.hasFocus){             this.setRawValue(this.emptyText);             this.el.addClass(this.emptyClass);         }     },     // private     preFocus : function(){         var el = this.el;         if(this.emptyText){             if(el.dom.value == this.emptyText){                 this.setRawValue('');             }             el.removeClass(this.emptyClass);         }         if(this.selectOnFocus){             (function(){                 el.dom.select();             }).defer(this.inEditor && Ext.isIE ? 50 : 0);             }     },     // private     postBlur : function(){         this.applyEmptyText();     },     // private     filterKeys : function(e){         // special keys don't generate charCodes, so leave them alone         if(e.ctrlKey || e.isSpecialKey()){             return;         }                  if(!this.maskRe.test(String.fromCharCode(e.getCharCode()))){             e.stopEvent();         }     },     setValue : function(v){         if(this.emptyText && this.el && !Ext.isEmpty(v)){             this.el.removeClass(this.emptyClass);         }         Ext.form.TextField.superclass.setValue.apply(this, arguments);         this.applyEmptyText();         this.autoSize();         return this;     },     /**      * Validates a value according to the field's validation rules and marks the field as invalid      * if the validation fails      * @param {Mixed} value The value to validate      * @return {Boolean} True if the value is valid, else false      */     validateValue : function(value){         if(Ext.isFunction(this.validator)){             var msg = this.validator(value);             if(msg !== true){                 this.markInvalid(msg);                 return false;             }         }         if(value.length < 1 || value === this.emptyText){ // if it's blank              if(this.allowBlank){                  this.clearInvalid();                  return true;              }else{                  this.markInvalid(this.blankText);                  return false;              }         }         if(value.length < this.minLength){             this.markInvalid(String.format(this.minLengthText, this.minLength));             return false;         }         if(value.length > this.maxLength){             this.markInvalid(String.format(this.maxLengthText, this.maxLength));             return false;         }         if(this.vtype){             var vt = Ext.form.VTypes;             if(!vt[this.vtype](value, this)){                 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);                 return false;             }         }         if(this.regex && !this.regex.test(value)){             this.markInvalid(this.regexText);             return false;         }         return true;     },     /**      * Selects text in this field      * @param {Number} start (optional) The index where the selection should start (defaults to 0)      * @param {Number} end (optional) The index where the selection should end (defaults to the text length)      */     selectText : function(start, end){         var v = this.getRawValue();         var doFocus = false;         if(v.length > 0){             start = start === undefined ? 0 : start;             end = end === undefined ? v.length : end;             var d = this.el.dom;             if(d.setSelectionRange){                 d.setSelectionRange(start, end);             }else if(d.createTextRange){                 var range = d.createTextRange();                 range.moveStart('character', start);                 range.moveEnd('character', end-v.length);                 range.select();             }             doFocus = Ext.isGecko || Ext.isOpera;         }else{             doFocus = true;         }         if(doFocus){             this.focus();         }     },     /**      * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.      * This only takes effect if <tt><b>{@link #grow}</b> = true</tt>, and fires the {@link #autosize} event.      */     autoSize : function(){         if(!this.grow || !this.rendered){             return;         }         if(!this.metrics){             this.metrics = Ext.util.TextMetrics.createInstance(this.el);         }         var el = this.el;         var v = el.dom.value;         var d = document.createElement('div');         d.appendChild(document.createTextNode(v));         v = d.innerHTML;         d = null;         Ext.removeNode(d);         v += '&#160;';         var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));         this.el.setWidth(w);         this.fireEvent('autosize', this, w);     }, onDestroy: function(){ if(this.validationTask){ this.validationTask.cancel(); this.validationTask = null; } Ext.form.TextField.superclass.onDestroy.call(this); } }); Ext.reg('textfield', Ext.form.TextField); /**  * @class Ext.form.TriggerField  * @extends Ext.form.TextField  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).  * The trigger has no default action, so you must assign a function to implement the trigger click handler by  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox  * for which you can provide a custom implementation.  For example:  * <pre><code> var trigger = new Ext.form.TriggerField(); trigger.onTriggerClick = myTriggerFn; trigger.applyToMarkup('my-field'); </code></pre>  *  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.  * {@link Ext.form.DateField} and {@link Ext.form.ComboBox} are perfect examples of this.  *   * @constructor  * Create a new TriggerField.  * @param {Object} config Configuration options (valid {@Ext.form.TextField} config options will also be applied  * to the base TextField)  * @xtype trigger  */ Ext.form.TriggerField = Ext.extend(Ext.form.TextField,  {     /**      * @cfg {String} triggerClass      * An additional CSS class used to style the trigger button.  The trigger will always get the      * class <tt>'x-form-trigger'</tt> by default and <tt>triggerClass</tt> will be <b>appended</b> if specified.      */     /**      * @cfg {Mixed} triggerConfig      * <p>A {@link Ext.DomHelper DomHelper} config object specifying the structure of the      * trigger element for this Field. (Optional).</p>      * <p>Specify this when you need a customized element to act as the trigger button for a TriggerField.</p>      * <p>Note that when using this option, it is the developer's responsibility to ensure correct sizing, positioning      * and appearance of the trigger.  Defaults to:</p>      * <pre><code>{tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass}</code></pre>      */     /**      * @cfg {String/Object} autoCreate <p>A {@link Ext.DomHelper DomHelper} element spec, or true for a default      * element spec. Used to create the {@link Ext.Component#getEl Element} which will encapsulate this Component.      * See <tt>{@link Ext.Component#autoEl autoEl}</tt> for details.  Defaults to:</p>      * <pre><code>{tag: "input", type: "text", size: "16", autocomplete: "off"}</code></pre>      */     defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},     /**      * @cfg {Boolean} hideTrigger <tt>true</tt> to hide the trigger element and display only the base      * text field (defaults to <tt>false</tt>)      */     hideTrigger:false,     /**      * @cfg {Boolean} editable <tt>false</tt> to prevent the user from typing text directly into the field,      * the field will only respond to a click on the trigger to set the value. (defaults to <tt>true</tt>)      */     editable: true,     /**      * @cfg {String} wrapFocusClass The class added to the to the wrap of the trigger element. Defaults to      * <tt>x-trigger-wrap-focus</tt>.      */     wrapFocusClass: 'x-trigger-wrap-focus',     /**      * @hide       * @method autoSize      */     autoSize: Ext.emptyFn,     // private     monitorTab : true,     // private     deferHeight : true,     // private     mimicing : false,          actionMode: 'wrap',     // private     onResize : function(w, h){         Ext.form.TriggerField.superclass.onResize.call(this, w, h);         if(typeof w == 'number'){             this.el.setWidth(this.adjustWidth('input', w - this.trigger.getWidth()));         }         this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());     },     // private     adjustSize : Ext.BoxComponent.prototype.adjustSize,     // private     getResizeEl : function(){         return this.wrap;     },     // private     getPositionEl : function(){         return this.wrap;     },     // private     alignErrorIcon : function(){         if(this.wrap){             this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);         }     },     // private     onRender : function(ct, position){         Ext.form.TriggerField.superclass.onRender.call(this, ct, position);         this.wrap = this.el.wrap({cls: 'x-form-field-wrap x-form-field-trigger-wrap'});         this.trigger = this.wrap.createChild(this.triggerConfig ||                 {tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});         if(this.hideTrigger){             this.trigger.setDisplayed(false);         }         this.initTrigger();         if(!this.width){             this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());         }         if(!this.editable){             this.editable = true;             this.setEditable(false);         }     },     afterRender : function(){         Ext.form.TriggerField.superclass.afterRender.call(this);     },     // private     initTrigger : function(){      this.mon(this.trigger, 'click', this.onTriggerClick, this, {preventDefault:true});         this.trigger.addClassOnOver('x-form-trigger-over');         this.trigger.addClassOnClick('x-form-trigger-click');     },     // private     onDestroy : function(){ Ext.destroy(this.trigger, this.wrap);         if (this.mimicing){             Ext.get(Ext.isIE ? document.body : document).un("mousedown", this.mimicBlur, this);         }         Ext.form.TriggerField.superclass.onDestroy.call(this);     },     // private     onFocus : function(){         Ext.form.TriggerField.superclass.onFocus.call(this);         if(!this.mimicing){             this.wrap.addClass(this.wrapFocusClass);             this.mimicing = true;             Ext.get(Ext.isIE ? document.body : document).on("mousedown", this.mimicBlur, this, {delay: 10});             if(this.monitorTab){              this.el.on('keydown', this.checkTab, this);             }         }     },     // private     checkTab : function(e){         if(e.getKey() == e.TAB){             this.triggerBlur();         }     },     // private     onBlur : function(){         // do nothing     },     // private     mimicBlur : function(e){         if(!this.wrap.contains(e.target) && this.validateBlur(e)){             this.triggerBlur();         }     },     // private     triggerBlur : function(){         this.mimicing = false;         Ext.get(Ext.isIE ? document.body : document).un("mousedown", this.mimicBlur, this);         if(this.monitorTab && this.el){             this.el.un("keydown", this.checkTab, this);         }         Ext.form.TriggerField.superclass.onBlur.call(this);         if(this.wrap){             this.wrap.removeClass(this.wrapFocusClass);         }     },     beforeBlur : Ext.emptyFn,           /**      * Allow or prevent the user from directly editing the field text.  If false is passed,      * the user will only be able to modify the field using the trigger.  This method      * is the runtime equivalent of setting the 'editable' config option at config time.      * @param {Boolean} value True to allow the user to directly edit the field text      */     setEditable : function(value){         if(value == this.editable){             return;         }         this.editable = value;         if(!value){             this.el.addClass('x-trigger-noedit').on('click', this.onTriggerClick, this).dom.setAttribute('readOnly', true);         }else{             this.el.removeClass('x-trigger-noedit').un('click', this.onTriggerClick,  this).dom.removeAttribute('readOnly');         }     },     // private     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.     validateBlur : function(e){         return true;     },     /**      * The function that should handle the trigger's click event.  This method does nothing by default      * until overridden by an implementing function.  See Ext.form.ComboBox and Ext.form.DateField for      * sample implementations.      * @method      * @param {EventObject} e      */     onTriggerClick : Ext.emptyFn     /**      * @cfg {Boolean} grow @hide      */     /**      * @cfg {Number} growMin @hide      */     /**      * @cfg {Number} growMax @hide      */ }); /**  * @class Ext.form.TwinTriggerField  * @extends Ext.form.TriggerField  * TwinTriggerField is not a public class to be used directly.  It is meant as an abstract base class  * to be extended by an implementing class.  For an example of implementing this class, see the custom  * SearchField implementation here:  * <a href="http://extjs.com/deploy/ext/examples/form/custom.html">http://extjs.com/deploy/ext/examples/form/custom.html</a>  */ Ext.form.TwinTriggerField = Ext.extend(Ext.form.TriggerField, {     /**      * @cfg {Mixed} triggerConfig      * <p>A {@link Ext.DomHelper DomHelper} config object specifying the structure of the trigger elements      * for this Field. (Optional).</p>      * <p>Specify this when you need a customized element to contain the two trigger elements for this Field.      * Each trigger element must be marked by the CSS class <tt>x-form-trigger</tt> (also see      * <tt>{@link #trigger1Class}</tt> and <tt>{@link #trigger2Class}</tt>).</p>      * <p>Note that when using this option, it is the developer's responsibility to ensure correct sizing,      * positioning and appearance of the triggers.</p>      */     /**      * @cfg {String} trigger1Class      * An additional CSS class used to style the trigger button.  The trigger will always get the      * class <tt>'x-form-trigger'</tt> by default and <tt>triggerClass</tt> will be <b>appended</b> if specified.      */     /**      * @cfg {String} trigger2Class      * An additional CSS class used to style the trigger button.  The trigger will always get the      * class <tt>'x-form-trigger'</tt> by default and <tt>triggerClass</tt> will be <b>appended</b> if specified.      */     initComponent : function(){         Ext.form.TwinTriggerField.superclass.initComponent.call(this);         this.triggerConfig = {             tag:'span', cls:'x-form-twin-triggers', cn:[             {tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},             {tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}         ]};     },     getTrigger : function(index){         return this.triggers[index];     },     initTrigger : function(){         var ts = this.trigger.select('.x-form-trigger', true);         this.wrap.setStyle('overflow', 'hidden');         var triggerField = this;         ts.each(function(t, all, index){             t.hide = function(){                 var w = triggerField.wrap.getWidth();                 this.dom.style.display = 'none';                 triggerField.el.setWidth(w-triggerField.trigger.getWidth());             };             t.show = function(){                 var w = triggerField.wrap.getWidth();                 this.dom.style.display = '';                 triggerField.el.setWidth(w-triggerField.trigger.getWidth());             };             var triggerIndex = 'Trigger'+(index+1);             if(this['hide'+triggerIndex]){                 t.dom.style.display = 'none';             }             this.mon(t, 'click', this['on'+triggerIndex+'Click'], this, {preventDefault:true});             t.addClassOnOver('x-form-trigger-over');             t.addClassOnClick('x-form-trigger-click');         }, this);         this.triggers = ts.elements;     },     /**      * The function that should handle the trigger's click event.  This method does nothing by default      * until overridden by an implementing function. See {@link Ext.form.TriggerField#onTriggerClick}      * for additional information.        * @method      * @param {EventObject} e      */     onTrigger1Click : Ext.emptyFn,     /**      * The function that should handle the trigger's click event.  This method does nothing by default      * until overridden by an implementing function. See {@link Ext.form.TriggerField#onTriggerClick}      * for additional information.        * @method      * @param {EventObject} e      */     onTrigger2Click : Ext.emptyFn }); Ext.reg('trigger', Ext.form.TriggerField);/**  * @class Ext.form.TextArea  * @extends Ext.form.TextField  * Multiline text field.  Can be used as a direct replacement for traditional textarea fields, plus adds  * support for auto-sizing.  * @constructor  * Creates a new TextArea  * @param {Object} config Configuration options  * @xtype textarea  */ Ext.form.TextArea = Ext.extend(Ext.form.TextField,  {     /**      * @cfg {Number} growMin The minimum height to allow when <tt>{@link Ext.form.TextField#grow grow}=true</tt>      * (defaults to <tt>60</tt>)      */     growMin : 60,     /**      * @cfg {Number} growMax The maximum height to allow when <tt>{@link Ext.form.TextField#grow grow}=true</tt>      * (defaults to <tt>1000</tt>)      */     growMax: 1000,     growAppend : '&#160;n&#160;',     growPad : Ext.isWebKit ? -6 : 0,     enterIsSpecial : false,     /**      * @cfg {Boolean} preventScrollbars <tt>true</tt> to prevent scrollbars from appearing regardless of how much text is      * in the field (equivalent to setting overflow: hidden, defaults to <tt>false</tt>)      */     preventScrollbars: false,     /**      * @cfg {String/Object} autoCreate <p>A {@link Ext.DomHelper DomHelper} element spec, or true for a default      * element spec. Used to create the {@link Ext.Component#getEl Element} which will encapsulate this Component.      * See <tt>{@link Ext.Component#autoEl autoEl}</tt> for details.  Defaults to:</p>      * <pre><code>{tag: "textarea", style: "width:100px;height:60px;", autocomplete: "off"}</code></pre>      */     // private     onRender : function(ct, position){         if(!this.el){             this.defaultAutoCreate = {                 tag: "textarea",                 style:"width:100px;height:60px;",                 autocomplete: "off"             };         }         Ext.form.TextArea.superclass.onRender.call(this, ct, position);         if(this.grow){             this.textSizeEl = Ext.DomHelper.append(document.body, {                 tag: "pre", cls: "x-form-grow-sizer"             });             if(this.preventScrollbars){                 this.el.setStyle("overflow", "hidden");             }             this.el.setHeight(this.growMin);         }     },     onDestroy : function(){         Ext.destroy(this.textSizeEl);         Ext.form.TextArea.superclass.onDestroy.call(this);     },     fireKey : function(e){         if(e.isSpecialKey() && (this.enterIsSpecial || (e.getKey() != e.ENTER || e.hasModifier()))){             this.fireEvent("specialkey", this, e);         }     },     // private     onKeyUp : function(e){         if(!e.isNavKeyPress() || e.getKey() == e.ENTER){             this.autoSize();         }         Ext.form.TextArea.superclass.onKeyUp.call(this, e);     },     /**      * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.      * This only takes effect if grow = true, and fires the {@link #autosize} event if the height changes.      */     autoSize: function(){         if(!this.grow || !this.textSizeEl){             return;         }         var el = this.el;         var v = el.dom.value;         var ts = this.textSizeEl;         ts.innerHTML = '';         ts.appendChild(document.createTextNode(v));         v = ts.innerHTML;         Ext.fly(ts).setWidth(this.el.getWidth());         if(v.length < 1){             v = "&#160;&#160;";         }else{             v += this.growAppend;             if(Ext.isIE){                 v = v.replace(/n/g, '<br />');             }         }         ts.innerHTML = v;         var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin) + this.growPad);         if(h != this.lastHeight){             this.lastHeight = h;             this.el.setHeight(h);             this.fireEvent("autosize", this, h);         }     } }); Ext.reg('textarea', Ext.form.TextArea);/**  * @class Ext.form.NumberField  * @extends Ext.form.TextField  * Numeric text field that provides automatic keystroke filtering and numeric validation.  * @constructor  * Creates a new NumberField  * @param {Object} config Configuration options  * @xtype numberfield  */ Ext.form.NumberField = Ext.extend(Ext.form.TextField,  {     /**      * @cfg {RegExp} stripCharsRe @hide      */     /**      * @cfg {RegExp} maskRe @hide      */     /**      * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")      */     fieldClass: "x-form-field x-form-num-field",     /**      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)      */     allowDecimals : true,     /**      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')      */     decimalSeparator : ".",     /**      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)      */     decimalPrecision : 2,     /**      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)      */     allowNegative : true,     /**      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)      */     minValue : Number.NEGATIVE_INFINITY,     /**      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)      */     maxValue : Number.MAX_VALUE,     /**      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")      */     minText : "The minimum value for this field is {0}",     /**      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")      */     maxText : "The maximum value for this field is {0}",     /**      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")      */     nanText : "{0} is not a valid number",     /**      * @cfg {String} baseChars The base set of characters to evaluate as valid numbers (defaults to '0123456789').      */     baseChars : "0123456789",     // private     initEvents : function(){         var allowed = this.baseChars + '';         if (this.allowDecimals) {             allowed += this.decimalSeparator;         }         if (this.allowNegative) {             allowed += '-';         }         this.maskRe = new RegExp('[' + Ext.escapeRe(allowed) + ']');         Ext.form.NumberField.superclass.initEvents.call(this);     },     // private     validateValue : function(value){         if(!Ext.form.NumberField.superclass.validateValue.call(this, value)){             return false;         }         if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid              return true;         }         value = String(value).replace(this.decimalSeparator, ".");         if(isNaN(value)){             this.markInvalid(String.format(this.nanText, value));             return false;         }         var num = this.parseValue(value);         if(num < this.minValue){             this.markInvalid(String.format(this.minText, this.minValue));             return false;         }         if(num > this.maxValue){             this.markInvalid(String.format(this.maxText, this.maxValue));             return false;         }         return true;     },     getValue : function(){         return this.fixPrecision(this.parseValue(Ext.form.NumberField.superclass.getValue.call(this)));     },     setValue : function(v){      v = typeof v == 'number' ? v : parseFloat(String(v).replace(this.decimalSeparator, "."));         v = isNaN(v) ? '' : String(v).replace(".", this.decimalSeparator);         return Ext.form.NumberField.superclass.setValue.call(this, v);     },     // private     parseValue : function(value){         value = parseFloat(String(value).replace(this.decimalSeparator, "."));         return isNaN(value) ? '' : value;     },     // private     fixPrecision : function(value){         var nan = isNaN(value);         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){            return nan ? '' : value;         }         return parseFloat(parseFloat(value).toFixed(this.decimalPrecision));     },     beforeBlur : function(){         var v = this.parseValue(this.getRawValue());         if(!Ext.isEmpty(v)){             this.setValue(this.fixPrecision(v));         }     } }); Ext.reg('numberfield', Ext.form.NumberField);/**  * @class Ext.form.DateField  * @extends Ext.form.TriggerField  * Provides a date input field with a {@link Ext.DatePicker} dropdown and automatic date validation.  * @constructor  * Create a new DateField  * @param {Object} config  * @xtype datefield  */ Ext.form.DateField = Ext.extend(Ext.form.TriggerField,  {     /**      * @cfg {String} format      * The default date format string which can be overriden for localization support.  The format must be      * valid according to {@link Date#parseDate} (defaults to <tt>'m/d/Y'</tt>).      */     format : "m/d/Y",     /**      * @cfg {String} altFormats      * Multiple date formats separated by "<tt>|</tt>" to try when parsing a user input value and it      * does not match the defined format (defaults to      * <tt>'m/d/Y|n/j/Y|n/j/y|m/j/y|n/d/y|m/j/Y|n/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d|Y-m-d'</tt>).      */     altFormats : "m/d/Y|n/j/Y|n/j/y|m/j/y|n/d/y|m/j/Y|n/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d|Y-m-d",     /**      * @cfg {String} disabledDaysText      * The tooltip to display when the date falls on a disabled day (defaults to <tt>'Disabled'</tt>)      */     disabledDaysText : "Disabled",     /**      * @cfg {String} disabledDatesText      * The tooltip text to display when the date falls on a disabled date (defaults to <tt>'Disabled'</tt>)      */     disabledDatesText : "Disabled",     /**      * @cfg {String} minText      * The error text to display when the date in the cell is before <tt>{@link #minValue}</tt> (defaults to      * <tt>'The date in this field must be after {minValue}'</tt>).      */     minText : "The date in this field must be equal to or after {0}",     /**      * @cfg {String} maxText      * The error text to display when the date in the cell is after <tt>{@link #maxValue}</tt> (defaults to      * <tt>'The date in this field must be before {maxValue}'</tt>).      */     maxText : "The date in this field must be equal to or before {0}",     /**      * @cfg {String} invalidText      * The error text to display when the date in the field is invalid (defaults to      * <tt>'{value} is not a valid date - it must be in the format {format}'</tt>).      */     invalidText : "{0} is not a valid date - it must be in the format {1}",     /**      * @cfg {String} triggerClass      * An additional CSS class used to style the trigger button.  The trigger will always get the      * class <tt>'x-form-trigger'</tt> and <tt>triggerClass</tt> will be <b>appended</b> if specified      * (defaults to <tt>'x-form-date-trigger'</tt> which displays a calendar icon).      */     triggerClass : 'x-form-date-trigger',     /**      * @cfg {Boolean} showToday      * <tt>false</tt> to hide the footer area of the DatePicker containing the Today button and disable      * the keyboard handler for spacebar that selects the current date (defaults to <tt>true</tt>).      */     showToday : true,     /**      * @cfg {Date/String} minValue      * The minimum allowed date. Can be either a Javascript date object or a string date in a      * valid format (defaults to null).      */     /**      * @cfg {Date/String} maxValue      * The maximum allowed date. Can be either a Javascript date object or a string date in a      * valid format (defaults to null).      */     /**      * @cfg {Array} disabledDays      * An array of days to disable, 0 based (defaults to null). Some examples:<pre><code> // disable Sunday and Saturday: disabledDays:  [0, 6] // disable weekdays: disabledDays: [1,2,3,4,5]      * </code></pre>      */     /**      * @cfg {Array} disabledDates      * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular      * expression so they are very powerful. Some examples:<pre><code> // disable these exact dates: disabledDates: ["03/08/2003", "09/16/2003"] // disable these days for every year: disabledDates: ["03/08", "09/16"] // only match the beginning (useful if you are using short years): disabledDates: ["^03/08"] // disable every day in March 2006: disabledDates: ["03/../2006"] // disable every day in every March: disabledDates: ["^03"]      * </code></pre>      * Note that the format of the dates included in the array should exactly match the {@link #format} config.      * In order to support regular expressions, if you are using a {@link #format date format} that has "." in      * it, you will have to escape the dot when restricting dates. For example: <tt>["03\.08\.03"]</tt>.      */     /**      * @cfg {String/Object} autoCreate      * A {@link Ext.DomHelper DomHelper element specification object}, or <tt>true</tt> for the default element      * specification object:<pre><code>      * autoCreate: {tag: "input", type: "text", size: "10", autocomplete: "off"}      * </code></pre>      */     // private     defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},     initComponent : function(){         Ext.form.DateField.superclass.initComponent.call(this);         this.addEvents(             /**              * @event select              * Fires when a date is selected via the date picker.              * @param {Ext.form.DateField} this              * @param {Date} date The date that was selected              */             'select'         );         if(Ext.isString(this.minValue)){             this.minValue = this.parseDate(this.minValue);         }         if(Ext.isString(this.maxValue)){             this.maxValue = this.parseDate(this.maxValue);         }         this.disabledDatesRE = null;         this.initDisabledDays();     },     // private     initDisabledDays : function(){         if(this.disabledDates){             var dd = this.disabledDates,                 len = dd.length - 1,                  re = "(?:";                              Ext.each(dd, function(d, i){                 re += Ext.isDate(d) ? '^' + Ext.escapeRe(d.dateFormat(this.format)) + '$' : dd[i];                 if(i != len){                     re += '|';                 }             }, this);             this.disabledDatesRE = new RegExp(re + ')');         }     },     /**      * Replaces any existing disabled dates with new values and refreshes the DatePicker.      * @param {Array} disabledDates An array of date strings (see the <tt>{@link #disabledDates}</tt> config      * for details on supported values) used to disable a pattern of dates.      */     setDisabledDates : function(dd){         this.disabledDates = dd;         this.initDisabledDays();         if(this.menu){             this.menu.picker.setDisabledDates(this.disabledDatesRE);         }     },     /**      * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker.      * @param {Array} disabledDays An array of disabled day indexes. See the <tt>{@link #disabledDays}</tt>      * config for details on supported values.      */     setDisabledDays : function(dd){         this.disabledDays = dd;         if(this.menu){             this.menu.picker.setDisabledDays(dd);         }     },     /**      * Replaces any existing <tt>{@link #minValue}</tt> with the new value and refreshes the DatePicker.      * @param {Date} value The minimum date that can be selected      */     setMinValue : function(dt){         this.minValue = (Ext.isString(dt) ? this.parseDate(dt) : dt);         if(this.menu){             this.menu.picker.setMinDate(this.minValue);         }     },     /**      * Replaces any existing <tt>{@link #maxValue}</tt> with the new value and refreshes the DatePicker.      * @param {Date} value The maximum date that can be selected      */     setMaxValue : function(dt){         this.maxValue = (Ext.isString(dt) ? this.parseDate(dt) : dt);         if(this.menu){             this.menu.picker.setMaxDate(this.maxValue);         }     },     // private     validateValue : function(value){         value = this.formatDate(value);         if(!Ext.form.DateField.superclass.validateValue.call(this, value)){             return false;         }         if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid              return true;         }         var svalue = value;         value = this.parseDate(value);         if(!value){             this.markInvalid(String.format(this.invalidText, svalue, this.format));             return false;         }         var time = value.getTime();         if(this.minValue && time < this.minValue.getTime()){             this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));             return false;         }         if(this.maxValue && time > this.maxValue.getTime()){             this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));             return false;         }         if(this.disabledDays){             var day = value.getDay();             for(var i = 0; i < this.disabledDays.length; i++) {                 if(day === this.disabledDays[i]){                     this.markInvalid(this.disabledDaysText);                     return false;                 }             }         }         var fvalue = this.formatDate(value);         if(this.disabledDatesRE && this.disabledDatesRE.test(fvalue)){             this.markInvalid(String.format(this.disabledDatesText, fvalue));             return false;         }         return true;     },     // private     // Provides logic to override the default TriggerField.validateBlur which just returns true     validateBlur : function(){         return !this.menu || !this.menu.isVisible();     },     /**      * Returns the current date value of the date field.      * @return {Date} The date value      */     getValue : function(){         return this.parseDate(Ext.form.DateField.superclass.getValue.call(this)) || "";     },     /**      * Sets the value of the date field.  You can pass a date object or any string that can be      * parsed into a valid date, using <tt>{@link #format}</tt> as the date format, according      * to the same rules as {@link Date#parseDate} (the default format used is <tt>"m/d/Y"</tt>).      * <br />Usage:      * <pre><code> //All of these calls set the same date value (May 4, 2006) //Pass a date object: var dt = new Date('5/4/2006'); dateField.setValue(dt); //Pass a date string (default format): dateField.setValue('05/04/2006'); //Pass a date string (custom format): dateField.format = 'Y-m-d'; dateField.setValue('2006-05-04'); </code></pre>      * @param {String/Date} date The date or valid date string      * @return {Ext.form.Field} this      */     setValue : function(date){         return Ext.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));     },     // private     parseDate : function(value){         if(!value || Ext.isDate(value)){             return value;         }         var v = Date.parseDate(value, this.format);         if(!v && this.altFormats){             if(!this.altFormatsArray){                 this.altFormatsArray = this.altFormats.split("|");             }             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){                 v = Date.parseDate(value, this.altFormatsArray[i]);             }         }         return v;     },     // private     onDestroy : function(){ Ext.destroy(this.menu);         Ext.form.DateField.superclass.onDestroy.call(this);     },     // private     formatDate : function(date){         return Ext.isDate(date) ? date.dateFormat(this.format) : date;     },     /**      * @method onTriggerClick      * @hide      */     // private     // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker     onTriggerClick : function(){         if(this.disabled){             return;         }         if(this.menu == null){             this.menu = new Ext.menu.DateMenu({                 hideOnClick: false             });         }         this.onFocus();         Ext.apply(this.menu.picker,  {             minDate : this.minValue,             maxDate : this.maxValue,             disabledDatesRE : this.disabledDatesRE,             disabledDatesText : this.disabledDatesText,             disabledDays : this.disabledDays,             disabledDaysText : this.disabledDaysText,             format : this.format,             showToday : this.showToday,             minText : String.format(this.minText, this.formatDate(this.minValue)),             maxText : String.format(this.maxText, this.formatDate(this.maxValue))         });         this.menu.picker.setValue(this.getValue() || new Date());         this.menu.show(this.el, "tl-bl?");         this.menuEvents('on');     },          //private     menuEvents: function(method){         this.menu[method]('select', this.onSelect, this);         this.menu[method]('hide', this.onMenuHide, this);         this.menu[method]('show', this.onFocus, this);     },          onSelect: function(m, d){         this.setValue(d);         this.fireEvent('select', this, d);         this.menu.hide();     },          onMenuHide: function(){         this.focus(false, 60);         this.menuEvents('un');     },     // private     beforeBlur : function(){         var v = this.parseDate(this.getRawValue());         if(v){             this.setValue(v);         }     }     /**      * @cfg {Boolean} grow @hide      */     /**      * @cfg {Number} growMin @hide      */     /**      * @cfg {Number} growMax @hide      */     /**      * @hide      * @method autoSize      */ }); Ext.reg('datefield', Ext.form.DateField);/**
  934.  * @class Ext.form.DisplayField
  935.  * @extends Ext.form.Field
  936.  * A display-only text field which is not validated and not submitted.
  937.  * @constructor
  938.  * Creates a new DisplayField.
  939.  * @param {Object} config Configuration options
  940.  * @xtype displayfield
  941.  */
  942. Ext.form.DisplayField = Ext.extend(Ext.form.Field,  {
  943.     validationEvent : false,
  944.     validateOnBlur : false,
  945.     defaultAutoCreate : {tag: "div"},
  946.     /**
  947.      * @cfg {String} fieldClass The default CSS class for the field (defaults to <tt>"x-form-display-field"</tt>)
  948.      */
  949.     fieldClass : "x-form-display-field",
  950.     /**
  951.      * @cfg {Boolean} htmlEncode <tt>false</tt> to skip HTML-encoding the text when rendering it (defaults to
  952.      * <tt>false</tt>). This might be useful if you want to include tags in the field's innerHTML rather than
  953.      * rendering them as string literals per the default logic.
  954.      */
  955.     htmlEncode: false,
  956.     // private
  957.     initEvents : Ext.emptyFn,
  958.     isValid : function(){
  959.         return true;
  960.     },
  961.     validate : function(){
  962.         return true;
  963.     },
  964.     getRawValue : function(){
  965.         var v = this.rendered ? this.el.dom.innerHTML : Ext.value(this.value, '');
  966.         if(v === this.emptyText){
  967.             v = '';
  968.         }
  969.         if(this.htmlEncode){
  970.             v = Ext.util.Format.htmlDecode(v);
  971.         }
  972.         return v;
  973.     },
  974.     getValue : function(){
  975.         return this.getRawValue();
  976.     },
  977.     
  978.     getName: function() {
  979.         return this.name;
  980.     },
  981.     setRawValue : function(v){
  982.         if(this.htmlEncode){
  983.             v = Ext.util.Format.htmlEncode(v);
  984.         }
  985.         return this.rendered ? (this.el.dom.innerHTML = (Ext.isEmpty(v) ? '' : v)) : (this.value = v);
  986.     },
  987.     setValue : function(v){
  988.         this.setRawValue(v);
  989.         return this;
  990.     }
  991.     /** 
  992.      * @cfg {String} inputType 
  993.      * @hide
  994.      */
  995.     /** 
  996.      * @cfg {Boolean} disabled 
  997.      * @hide
  998.      */
  999.     /** 
  1000.      * @cfg {Boolean} readOnly 
  1001.      * @hide
  1002.      */
  1003.     /** 
  1004.      * @cfg {Boolean} validateOnBlur 
  1005.      * @hide
  1006.      */
  1007.     /** 
  1008.      * @cfg {Number} validationDelay 
  1009.      * @hide
  1010.      */
  1011.     /** 
  1012.      * @cfg {String/Boolean} validationEvent 
  1013.      * @hide
  1014.      */
  1015. });
  1016. Ext.reg('displayfield', Ext.form.DisplayField);
  1017. /**  * @class Ext.form.ComboBox  * @extends Ext.form.TriggerField  * <p>A combobox control with support for autocomplete, remote-loading, paging and many other features.</p>  * <p>A ComboBox works in a similar manner to a traditional HTML &lt;select> field. The difference is  * that to submit the {@link #valueField}, you must specify a {@link #hiddenName} to create a hidden input  * field to hold the value of the valueField. The <i>{@link #displayField}</i> is shown in the text field  * which is named according to the {@link #name}.</p>  * <p><b><u>Events</u></b></p>  * <p>To do something when something in ComboBox is selected, configure the select event:<pre><code> var cb = new Ext.form.ComboBox({     // all of your config options     listeners:{          scope: yourScope,          'select': yourFunction     } }); // Alternatively, you can assign events after the object is created: var cb = new Ext.form.ComboBox(yourOptions); cb.on('select', yourFunction, yourScope);  * </code></pre></p>  *  * <p><b><u>ComboBox in Grid</u></b></p>  * <p>If using a ComboBox in an {@link Ext.grid.EditorGridPanel Editor Grid} a {@link Ext.grid.Column#renderer renderer}  * will be needed to show the displayField when the editor is not active.  Set up the renderer manually, or implement  * a reusable render, for example:<pre><code> // create reusable renderer Ext.util.Format.comboRenderer = function(combo){     return function(value){         var record = combo.findRecord(combo.{@link #valueField}, value);         return record ? record.get(combo.{@link #displayField}) : combo.{@link #valueNotFoundText};     } } // create the combo instance var combo = new Ext.form.ComboBox({     {@link #typeAhead}: true,     {@link #triggerAction}: 'all',     {@link #lazyRender}:true,     {@link #mode}: 'local',     {@link #store}: new Ext.data.ArrayStore({         id: 0,         fields: [             'myId',             'displayText'         ],         data: [[1, 'item1'], [2, 'item2']]     }),     {@link #valueField}: 'myId',     {@link #displayField}: 'displayText' }); // snippet of column model used within grid var cm = new Ext.grid.ColumnModel([{        ...     },{        header: "Some Header",        dataIndex: 'whatever',        width: 130,        editor: combo, // specify reference to combo instance        renderer: Ext.util.Format.comboRenderer(combo) // pass combo instance to reusable renderer     },     ... ]);  * </code></pre></p>  *  * <p><b><u>Filtering</u></b></p>  * <p>A ComboBox {@link #doQuery uses filtering itself}, for information about filtering the ComboBox  * store manually see <tt>{@link #lastQuery}</tt>.</p>  * @constructor  * Create a new ComboBox.  * @param {Object} config Configuration options  * @xtype combo  */ Ext.form.ComboBox = Ext.extend(Ext.form.TriggerField, {     /**      * @cfg {Mixed} transform The id, DOM node or element of an existing HTML SELECT to convert to a ComboBox.      * Note that if you specify this and the combo is going to be in an {@link Ext.form.BasicForm} or      * {@link Ext.form.FormPanel}, you must also set <tt>{@link #lazyRender} = true</tt>.      */     /**      * @cfg {Boolean} lazyRender <tt>true</tt> to prevent the ComboBox from rendering until requested      * (should always be used when rendering into an {@link Ext.Editor} (e.g. {@link Ext.grid.EditorGridPanel Grids}),      * defaults to <tt>false</tt>).      */     /**      * @cfg {String/Object} autoCreate <p>A {@link Ext.DomHelper DomHelper} element spec, or <tt>true</tt> for a default      * element spec. Used to create the {@link Ext.Component#getEl Element} which will encapsulate this Component.      * See <tt>{@link Ext.Component#autoEl autoEl}</tt> for details.  Defaults to:</p>      * <pre><code>{tag: "input", type: "text", size: "24", autocomplete: "off"}</code></pre>      */     /**      * @cfg {Ext.data.Store/Array} store The data source to which this combo is bound (defaults to <tt>undefined</tt>).      * Acceptable values for this property are:      * <div class="mdetail-params"><ul>      * <li><b>any {@link Ext.data.Store Store} subclass</b></li>      * <li><b>an Array</b> : Arrays will be converted to a {@link Ext.data.ArrayStore} internally.      * <div class="mdetail-params"><ul>      * <li><b>1-dimensional array</b> : (e.g., <tt>['Foo','Bar']</tt>)<div class="sub-desc">      * A 1-dimensional array will automatically be expanded (each array item will be the combo      * {@link #valueField value} and {@link #displayField text})</div></li>      * <li><b>2-dimensional array</b> : (e.g., <tt>[['f','Foo'],['b','Bar']]</tt>)<div class="sub-desc">      * For a multi-dimensional array, the value in index 0 of each item will be assumed to be the combo      * {@link #valueField value}, while the value at index 1 is assumed to be the combo {@link #displayField text}.      * </div></li></ul></div></li></ul></div>      * <p>See also <tt>{@link #mode}</tt>.</p>      */     /**      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of      * the dropdown list (defaults to undefined, with no header element)      */     // private     defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},     /**      * @cfg {Number} listWidth The width (used as a parameter to {@link Ext.Element#setWidth}) of the dropdown      * list (defaults to the width of the ComboBox field).  See also <tt>{@link #minListWidth}      */     /**      * @cfg {String} displayField The underlying {@link Ext.data.Field#name data field name} to bind to this      * ComboBox (defaults to undefined if <tt>{@link #mode} = 'remote'</tt> or <tt>'text'</tt> if      * {@link #transform transforming a select} a select).      * <p>See also <tt>{@link #valueField}</tt>.</p>      * <p><b>Note</b>: if using a ComboBox in an {@link Ext.grid.EditorGridPanel Editor Grid} a      * {@link Ext.grid.Column#renderer renderer} will be needed to show the displayField when the editor is not      * active.</p>      */     /**      * @cfg {String} valueField The underlying {@link Ext.data.Field#name data value name} to bind to this      * ComboBox (defaults to undefined if <tt>{@link #mode} = 'remote'</tt> or <tt>'value'</tt> if      * {@link #transform transforming a select}).      * <p><b>Note</b>: use of a <tt>valueField</tt> requires the user to make a selection in order for a value to be      * mapped.  See also <tt>{@link #hiddenName}</tt>, <tt>{@link #hiddenValue}</tt>, and <tt>{@link #displayField}</tt>.</p>      */     /**      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the      * field's data value (defaults to the underlying DOM element's name). Required for the combo's value to automatically      * post during a form submission.  See also {@link #valueField}.      * <p><b>Note</b>: the hidden field's id will also default to this name if {@link #hiddenId} is not specified.      * The ComboBox {@link Ext.Component#id id} and the <tt>{@link #hiddenId}</tt> <b>should be different</b>, since      * no two DOM nodes should share the same id.  So, if the ComboBox <tt>{@link Ext.form.Field#name name}</tt> and      * <tt>hiddenName</tt> are the same, you should specify a unique <tt>{@link #hiddenId}</tt>.</p>      */     /**      * @cfg {String} hiddenId If <tt>{@link #hiddenName}</tt> is specified, <tt>hiddenId</tt> can also be provided      * to give the hidden field a unique id (defaults to the <tt>{@link #hiddenName}</tt>).  The <tt>hiddenId</tt>      * and combo {@link Ext.Component#id id} should be different, since no two DOM      * nodes should share the same id.      */     /**      * @cfg {String} hiddenValue Sets the initial value of the hidden field if {@link #hiddenName} is      * specified to contain the selected {@link #valueField}, from the Store. Defaults to the configured      * <tt>{@link Ext.form.Field#value value}</tt>.      */     /**      * @cfg {String} listClass The CSS class to add to the predefined <tt>'x-combo-list'</tt> class      * applied the dropdown list element (defaults to '').      */     listClass : '',     /**      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list      * (defaults to <tt>'x-combo-selected'</tt>)      */     selectedClass : 'x-combo-selected',     /**      * @cfg {String} listEmptyText The empty text to display in the data view if no items are found.      * (defaults to '')      */     listEmptyText: '',     /**      * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always      * get the class <tt>'x-form-trigger'</tt> and <tt>triggerClass</tt> will be <b>appended</b> if specified      * (defaults to <tt>'x-form-arrow-trigger'</tt> which displays a downward arrow icon).      */     triggerClass : 'x-form-arrow-trigger',     /**      * @cfg {Boolean/String} shadow <tt>true</tt> or <tt>"sides"</tt> for the default effect, <tt>"frame"</tt> for      * 4-way shadow, and <tt>"drop"</tt> for bottom-right      */     shadow : 'sides',     /**      * @cfg {String} listAlign A valid anchor position value. See <tt>{@link Ext.Element#alignTo}</tt> for details      * on supported anchor positions (defaults to <tt>'tl-bl?'</tt>)      */     listAlign : 'tl-bl?',     /**      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown      * (defaults to <tt>300</tt>)      */     maxHeight : 300,     /**      * @cfg {Number} minHeight The minimum height in pixels of the dropdown list when the list is constrained by its      * distance to the viewport edges (defaults to <tt>90</tt>)      */     minHeight : 90,     /**      * @cfg {String} triggerAction The action to execute when the trigger is clicked.      * <div class="mdetail-params"><ul>      * <li><b><tt>'query'</tt></b> : <b>Default</b>      * <p class="sub-desc">{@link #doQuery run the query} using the {@link Ext.form.Field#getRawValue raw value}.</p></li>      * <li><b><tt>'all'</tt></b> :      * <p class="sub-desc">{@link #doQuery run the query} specified by the <tt>{@link #allQuery}</tt> config option</p></li>      * </ul></div>      * <p>See also <code>{@link #queryParam}</code>.</p>      */     triggerAction : 'query',     /**      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and      * {@link #typeAhead} activate (defaults to <tt>4</tt> if <tt>{@link #mode} = 'remote'</tt> or <tt>0</tt> if      * <tt>{@link #mode} = 'local'</tt>, does not apply if      * <tt>{@link Ext.form.TriggerField#editable editable} = false</tt>).      */     minChars : 4,     /**      * @cfg {Boolean} typeAhead <tt>true</tt> to populate and autoselect the remainder of the text being      * typed after a configurable delay ({@link #typeAheadDelay}) if it matches a known value (defaults      * to <tt>false</tt>)      */     typeAhead : false,     /**      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and      * sending the query to filter the dropdown list (defaults to <tt>500</tt> if <tt>{@link #mode} = 'remote'</tt>      * or <tt>10</tt> if <tt>{@link #mode} = 'local'</tt>)      */     queryDelay : 500,     /**      * @cfg {Number} pageSize If greater than <tt>0</tt>, a {@link Ext.PagingToolbar} is displayed in the      * footer of the dropdown list and the {@link #doQuery filter queries} will execute with page start and      * {@link Ext.PagingToolbar#pageSize limit} parameters. Only applies when <tt>{@link #mode} = 'remote'</tt>      * (defaults to <tt>0</tt>).      */     pageSize : 0,     /**      * @cfg {Boolean} selectOnFocus <tt>true</tt> to select any existing text in the field immediately on focus.      * Only applies when <tt>{@link Ext.form.TriggerField#editable editable} = true</tt> (defaults to      * <tt>false</tt>).      */     selectOnFocus : false,     /**      * @cfg {String} queryParam Name of the query ({@link Ext.data.Store#baseParam baseParam} name for the store)      * as it will be passed on the querystring (defaults to <tt>'query'</tt>)      */     queryParam : 'query',     /**      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies      * when <tt>{@link #mode} = 'remote'</tt> (defaults to <tt>'Loading...'</tt>)      */     loadingText : 'Loading...',     /**      * @cfg {Boolean} resizable <tt>true</tt> to add a resize handle to the bottom of the dropdown list      * (creates an {@link Ext.Resizable} with 'se' {@link Ext.Resizable#pinned pinned} handles).      * Defaults to <tt>false</tt>.      */     resizable : false,     /**      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if      * <tt>{@link #resizable} = true</tt> (defaults to <tt>8</tt>)      */     handleHeight : 8,     /**      * @cfg {String} allQuery The text query to send to the server to return all records for the list      * with no filtering (defaults to '')      */     allQuery: '',     /**      * @cfg {String} mode Acceptable values are:      * <div class="mdetail-params"><ul>      * <li><b><tt>'remote'</tt></b> : <b>Default</b>      * <p class="sub-desc">Automatically loads the <tt>{@link #store}</tt> the <b>first</b> time the trigger      * is clicked. If you do not want the store to be automatically loaded the first time the trigger is      * clicked, set to <tt>'local'</tt> and manually load the store.  To force a requery of the store      * <b>every</b> time the trigger is clicked see <tt>{@link #lastQuery}</tt>.</p></li>      * <li><b><tt>'local'</tt></b> :      * <p class="sub-desc">ComboBox loads local data</p>      * <pre><code> var combo = new Ext.form.ComboBox({     renderTo: document.body,     mode: 'local',     store: new Ext.data.ArrayStore({         id: 0,         fields: [             'myId',  // numeric value is the key             'displayText'         ],         data: [[1, 'item1'], [2, 'item2']]  // data is local     }),     valueField: 'myId',     displayField: 'displayText',     triggerAction: 'all' });      * </code></pre></li>      * </ul></div>      */     mode: 'remote',     /**      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to <tt>70</tt>, will      * be ignored if <tt>{@link #listWidth}</tt> has a higher value)      */     minListWidth : 70,     /**      * @cfg {Boolean} forceSelection <tt>true</tt> to restrict the selected value to one of the values in the list,      * <tt>false</tt> to allow the user to set arbitrary text into the field (defaults to <tt>false</tt>)      */     forceSelection : false,     /**      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed      * if <tt>{@link #typeAhead} = true</tt> (defaults to <tt>250</tt>)      */     typeAheadDelay : 250,     /**      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined). If this      * default text is used, it means there is no value set and no validation will occur on this field.      */     /**      * @cfg {Boolean} lazyInit <tt>true</tt> to not initialize the list for this combo until the field is focused      * (defaults to <tt>true</tt>)      */     lazyInit : true,     /**      * The value of the match string used to filter the store. Delete this property to force a requery.      * Example use:      * <pre><code> var combo = new Ext.form.ComboBox({     ...     mode: 'remote',     ...     listeners: {         // delete the previous query in the beforequery event or set         // combo.lastQuery = null (this will reload the store the next time it expands)         beforequery: function(qe){             delete qe.combo.lastQuery;         }     } });      * </code></pre>      * To make sure the filter in the store is not cleared the first time the ComboBox trigger is used      * configure the combo with <tt>lastQuery=''</tt>. Example use:      * <pre><code> var combo = new Ext.form.ComboBox({     ...     mode: 'local',     triggerAction: 'all',     lastQuery: '' });      * </code></pre>      * @property lastQuery      * @type String      */     // private     initComponent : function(){         Ext.form.ComboBox.superclass.initComponent.call(this);         this.addEvents(             /**              * @event expand              * Fires when the dropdown list is expanded              * @param {Ext.form.ComboBox} combo This combo box              */             'expand',             /**              * @event collapse              * Fires when the dropdown list is collapsed              * @param {Ext.form.ComboBox} combo This combo box              */             'collapse',             /**              * @event beforeselect              * Fires before a list item is selected. Return false to cancel the selection.              * @param {Ext.form.ComboBox} combo This combo box              * @param {Ext.data.Record} record The data record returned from the underlying store              * @param {Number} index The index of the selected item in the dropdown list              */             'beforeselect',             /**              * @event select              * Fires when a list item is selected              * @param {Ext.form.ComboBox} combo This combo box              * @param {Ext.data.Record} record The data record returned from the underlying store              * @param {Number} index The index of the selected item in the dropdown list              */             'select',             /**              * @event beforequery              * Fires before all queries are processed. Return false to cancel the query or set the queryEvent's              * cancel property to true.              * @param {Object} queryEvent An object that has these properties:<ul>              * <li><code>combo</code> : Ext.form.ComboBox <div class="sub-desc">This combo box</div></li>              * <li><code>query</code> : String <div class="sub-desc">The query</div></li>              * <li><code>forceAll</code> : Boolean <div class="sub-desc">True to force "all" query</div></li>              * <li><code>cancel</code> : Boolean <div class="sub-desc">Set to true to cancel the query</div></li>              * </ul>              */             'beforequery'         );         if(this.transform){             var s = Ext.getDom(this.transform);             if(!this.hiddenName){                 this.hiddenName = s.name;             }             if(!this.store){                 this.mode = 'local';                 var d = [], opts = s.options;                 for(var i = 0, len = opts.length;i < len; i++){                     var o = opts[i],                         value = (o.hasAttribute ? o.hasAttribute('value') : o.getAttributeNode('value').specified) ? o.value : o.text;                     if(o.selected && Ext.isEmpty(this.value, true)) {                         this.value = value;                     }                     d.push([value, o.text]);                 }                 this.store = new Ext.data.ArrayStore({                     'id': 0,                     fields: ['value', 'text'],                     data : d,                     autoDestroy: true                 });                 this.valueField = 'value';                 this.displayField = 'text';             }             s.name = Ext.id(); // wipe out the name in case somewhere else they have a reference             if(!this.lazyRender){                 this.target = true;                 this.el = Ext.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);                 this.render(this.el.parentNode, s);                 Ext.removeNode(s); // remove it             }else{                 Ext.removeNode(s); // remove it             }         }         //auto-configure store from local array data         else if(this.store){             this.store = Ext.StoreMgr.lookup(this.store);             if(this.store.autoCreated){                 this.displayField = this.valueField = 'field1';                 if(!this.store.expandData){                     this.displayField = 'field2';                 }                 this.mode = 'local';             }         }         this.selectedIndex = -1;         if(this.mode == 'local'){             if(!Ext.isDefined(this.initialConfig.queryDelay)){                 this.queryDelay = 10;             }             if(!Ext.isDefined(this.initialConfig.minChars)){                 this.minChars = 0;             }         }     },     // private     onRender : function(ct, position){         Ext.form.ComboBox.superclass.onRender.call(this, ct, position);         if(this.hiddenName){             this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName,                     id: (this.hiddenId||this.hiddenName)}, 'before', true);             // prevent input submission             this.el.dom.removeAttribute('name');         }         if(Ext.isGecko){             this.el.dom.setAttribute('autocomplete', 'off');         }         if(!this.lazyInit){             this.initList();         }else{             this.on('focus', this.initList, this, {single: true});         }     },     // private     initValue : function(){         Ext.form.ComboBox.superclass.initValue.call(this);         if(this.hiddenField){             this.hiddenField.value =                 Ext.isDefined(this.hiddenValue) ? this.hiddenValue :                 Ext.isDefined(this.value) ? this.value : '';         }     },     // private     initList : function(){         if(!this.list){             var cls = 'x-combo-list';             this.list = new Ext.Layer({                 parentEl: this.getListParent(),                 shadow: this.shadow,                 cls: [cls, this.listClass].join(' '),                 constrain:false             });             var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);             this.list.setSize(lw, 0);             this.list.swallowEvent('mousewheel');             this.assetHeight = 0;             if(this.syncFont !== false){                 this.list.setStyle('font-size', this.el.getStyle('font-size'));             }             if(this.title){                 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});                 this.assetHeight += this.header.getHeight();             }             this.innerList = this.list.createChild({cls:cls+'-inner'});             this.mon(this.innerList, 'mouseover', this.onViewOver, this);             this.mon(this.innerList, 'mousemove', this.onViewMove, this);             this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));             if(this.pageSize){                 this.footer = this.list.createChild({cls:cls+'-ft'});                 this.pageTb = new Ext.PagingToolbar({                     store: this.store,                     pageSize: this.pageSize,                     renderTo:this.footer                 });                 this.assetHeight += this.footer.getHeight();             }             if(!this.tpl){                 /**                 * @cfg {String/Ext.XTemplate} tpl <p>The template string, or {@link Ext.XTemplate} instance to                 * use to display each item in the dropdown list. The dropdown list is displayed in a                 * DataView. See {@link #view}.</p>                 * <p>The default template string is:</p><pre><code>                   '&lt;tpl for=".">&lt;div class="x-combo-list-item">{' + this.displayField + '}&lt;/div>&lt;/tpl>'                 * </code></pre>                 * <p>Override the default value to create custom UI layouts for items in the list.                 * For example:</p><pre><code>                   '&lt;tpl for=".">&lt;div ext:qtip="{state}. {nick}" class="x-combo-list-item">{state}&lt;/div>&lt;/tpl>'                 * </code></pre>                 * <p>The template <b>must</b> contain one or more substitution parameters using field                 * names from the Combo's</b> {@link #store Store}. In the example above an                 * <pre>ext:qtip</pre> attribute is added to display other fields from the Store.</p>                 * <p>To preserve the default visual look of list items, add the CSS class name                 * <pre>x-combo-list-item</pre> to the template's container element.</p>                 * <p>Also see {@link #itemSelector} for additional details.</p>                 */                 this.tpl = '<tpl for="."><div class="'+cls+'-item">{' + this.displayField + '}</div></tpl>';                 /**                  * @cfg {String} itemSelector                  * <p>A simple CSS selector (e.g. div.some-class or span:first-child) that will be                  * used to determine what nodes the {@link #view Ext.DataView} which handles the dropdown                  * display will be working with.</p>                  * <p><b>Note</b>: this setting is <b>required</b> if a custom XTemplate has been                  * specified in {@link #tpl} which assigns a class other than <pre>'x-combo-list-item'</pre>                  * to dropdown list items</b>                  */             }             /**             * The {@link Ext.DataView DataView} used to display the ComboBox's options.             * @type Ext.DataView             */             this.view = new Ext.DataView({                 applyTo: this.innerList,                 tpl: this.tpl,                 singleSelect: true,                 selectedClass: this.selectedClass,                 itemSelector: this.itemSelector || '.' + cls + '-item',                 emptyText: this.listEmptyText             });             this.mon(this.view, 'click', this.onViewClick, this);             this.bindStore(this.store, true);             if(this.resizable){                 this.resizer = new Ext.Resizable(this.list,  {                    pinned:true, handles:'se'                 });                 this.mon(this.resizer, 'resize', function(r, w, h){                     this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;                     this.listWidth = w;                     this.innerList.setWidth(w - this.list.getFrameWidth('lr'));                     this.restrictHeight();                 }, this);                 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');             }         }     },     /**      * <p>Returns the element used to house this ComboBox's pop-up list. Defaults to the document body.</p>      * A custom implementation may be provided as a configuration option if the floating list needs to be rendered      * to a different Element. An example might be rendering the list inside a Menu so that clicking      * the list does not hide the Menu:<pre><code> var store = new Ext.data.ArrayStore({     autoDestroy: true,     fields: ['initials', 'fullname'],     data : [         ['FF', 'Fred Flintstone'],         ['BR', 'Barney Rubble']     ] }); var combo = new Ext.form.ComboBox({     store: store,     displayField: 'fullname',     emptyText: 'Select a name...',     forceSelection: true,     getListParent: function() {         return this.el.up('.x-menu');     },     iconCls: 'no-icon', //use iconCls if placing within menu to shift to right side of menu     mode: 'local',     selectOnFocus: true,     triggerAction: 'all',     typeAhead: true,     width: 135 }); var menu = new Ext.menu.Menu({     id: 'mainMenu',     items: [         combo // A Field in a Menu     ] }); </code></pre>      */     getListParent : function() {         return document.body;     },     /**      * Returns the store associated with this combo.      * @return {Ext.data.Store} The store      */     getStore : function(){         return this.store;     },     // private     bindStore : function(store, initial){         if(this.store && !initial){             this.store.un('beforeload', this.onBeforeLoad, this);             this.store.un('load', this.onLoad, this);             this.store.un('exception', this.collapse, this);             if(this.store !== store && this.store.autoDestroy){                 this.store.destroy();             }             if(!store){                 this.store = null;                 if(this.view){                     this.view.bindStore(null);                 }             }         }         if(store){             if(!initial) {                 this.lastQuery = null;                 if(this.pageTb) {                     this.pageTb.bindStore(store);                 }             }             this.store = Ext.StoreMgr.lookup(store);             this.store.on({                 scope: this,                 beforeload: this.onBeforeLoad,                 load: this.onLoad,                 exception: this.collapse             });             if(this.view){                 this.view.bindStore(store);             }         }     },     // private     initEvents : function(){         Ext.form.ComboBox.superclass.initEvents.call(this);         this.keyNav = new Ext.KeyNav(this.el, {             "up" : function(e){                 this.inKeyMode = true;                 this.selectPrev();             },             "down" : function(e){                 if(!this.isExpanded()){                     this.onTriggerClick();                 }else{                     this.inKeyMode = true;                     this.selectNext();                 }             },             "enter" : function(e){                 this.onViewClick();                 this.delayedCheck = true;                 this.unsetDelayCheck.defer(10, this);             },             "esc" : function(e){                 this.collapse();             },             "tab" : function(e){                 this.onViewClick(false);                 return true;             },             scope : this,             doRelay : function(foo, bar, hname){                 if(hname == 'down' || this.scope.isExpanded()){                    return Ext.KeyNav.prototype.doRelay.apply(this, arguments);                 }                 return true;             },             forceKeyDown : true         });         this.queryDelay = Math.max(this.queryDelay || 10,                 this.mode == 'local' ? 10 : 250);         this.dqTask = new Ext.util.DelayedTask(this.initQuery, this);         if(this.typeAhead){             this.taTask = new Ext.util.DelayedTask(this.onTypeAhead, this);         }         if(this.editable !== false && !this.enableKeyEvents){             this.mon(this.el, 'keyup', this.onKeyUp, this);         }     },     // private     onDestroy : function(){         if (this.dqTask){             this.dqTask.cancel();             this.dqTask = null;         }         this.bindStore(null);         Ext.destroy(             this.resizer,             this.view,             this.pageTb,             this.list         );         Ext.form.ComboBox.superclass.onDestroy.call(this);     },     // private     unsetDelayCheck : function(){         delete this.delayedCheck;     },     // private     fireKey : function(e){         var fn = function(ev){             if (ev.isNavKeyPress() && !this.isExpanded() && !this.delayedCheck) {                 this.fireEvent("specialkey", this, ev);             }         };         //For some reason I can't track down, the events fire in a different order in webkit.         //Need a slight delay here         if(this.inEditor && Ext.isWebKit && e.getKey() == e.TAB){             fn.defer(10, this, [new Ext.EventObjectImpl(e)]);         }else{             fn.call(this, e);         }     },     // private     onResize : function(w, h){         Ext.form.ComboBox.superclass.onResize.apply(this, arguments);         if(this.list && !Ext.isDefined(this.listWidth)){             var lw = Math.max(w, this.minListWidth);             this.list.setWidth(lw);             this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));         }     },     // private     onEnable : function(){         Ext.form.ComboBox.superclass.onEnable.apply(this, arguments);         if(this.hiddenField){             this.hiddenField.disabled = false;         }     },     // private     onDisable : function(){         Ext.form.ComboBox.superclass.onDisable.apply(this, arguments);         if(this.hiddenField){             this.hiddenField.disabled = true;         }     },     // private     onBeforeLoad : function(){         if(!this.hasFocus){             return;         }         this.innerList.update(this.loadingText ?                '<div class="loading-indicator">'+this.loadingText+'</div>' : '');         this.restrictHeight();         this.selectedIndex = -1;     },     // private     onLoad : function(){         if(!this.hasFocus){             return;         }         if(this.store.getCount() > 0){             this.expand();             this.restrictHeight();             if(this.lastQuery == this.allQuery){                 if(this.editable){                     this.el.dom.select();                 }                 if(!this.selectByValue(this.value, true)){                     this.select(0, true);                 }             }else{                 this.selectNext();                 if(this.typeAhead && this.lastKey != Ext.EventObject.BACKSPACE && this.lastKey != Ext.EventObject.DELETE){                     this.taTask.delay(this.typeAheadDelay);                 }             }         }else{             this.onEmptyResults();         }         //this.el.focus();     },     // private     onTypeAhead : function(){         if(this.store.getCount() > 0){             var r = this.store.getAt(0);             var newValue = r.data[this.displayField];             var len = newValue.length;             var selStart = this.getRawValue().length;             if(selStart != len){                 this.setRawValue(newValue);                 this.selectText(selStart, newValue.length);             }         }     },     // private     onSelect : function(record, index){         if(this.fireEvent('beforeselect', this, record, index) !== false){             this.setValue(record.data[this.valueField || this.displayField]);             this.collapse();             this.fireEvent('select', this, record, index);         }     },     // inherit docs     getName: function(){         var hf = this.hiddenField;         return hf && hf.name ? hf.name : this.hiddenName || Ext.form.ComboBox.superclass.getName.call(this);     },     /**      * Returns the currently selected field value or empty string if no value is set.      * @return {String} value The selected value      */     getValue : function(){         if(this.valueField){             return Ext.isDefined(this.value) ? this.value : '';         }else{             return Ext.form.ComboBox.superclass.getValue.call(this);         }     },     /**      * Clears any text/value currently set in the field      */     clearValue : function(){         if(this.hiddenField){             this.hiddenField.value = '';         }         this.setRawValue('');         this.lastSelectionText = '';         this.applyEmptyText();         this.value = '';     },     /**      * Sets the specified value into the field.  If the value finds a match, the corresponding record text      * will be displayed in the field.  If the value does not match the data value of an existing item,      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.      * Otherwise the field will be blank (although the value will still be set).      * @param {String} value The value to match      * @return {Ext.form.Field} this      */     setValue : function(v){         var text = v;         if(this.valueField){             var r = this.findRecord(this.valueField, v);             if(r){                 text = r.data[this.displayField];             }else if(Ext.isDefined(this.valueNotFoundText)){                 text = this.valueNotFoundText;             }         }         this.lastSelectionText = text;         if(this.hiddenField){             this.hiddenField.value = v;         }         Ext.form.ComboBox.superclass.setValue.call(this, text);         this.value = v;         return this;     },     // private     findRecord : function(prop, value){         var record;         if(this.store.getCount() > 0){             this.store.each(function(r){                 if(r.data[prop] == value){                     record = r;                     return false;                 }             });         }         return record;     },     // private     onViewMove : function(e, t){         this.inKeyMode = false;     },     // private     onViewOver : function(e, t){         if(this.inKeyMode){ // prevent key nav and mouse over conflicts             return;         }         var item = this.view.findItemFromChild(t);         if(item){             var index = this.view.indexOf(item);             this.select(index, false);         }     },     // private     onViewClick : function(doFocus){         var index = this.view.getSelectedIndexes()[0];         var r = this.store.getAt(index);         if(r){             this.onSelect(r, index);         }         if(doFocus !== false){             this.el.focus();         }     },     // private     restrictHeight : function(){         this.innerList.dom.style.height = '';         var inner = this.innerList.dom;         var pad = this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight;         var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);         var ha = this.getPosition()[1]-Ext.getBody().getScroll().top;         var hb = Ext.lib.Dom.getViewHeight()-ha-this.getSize().height;         var space = Math.max(ha, hb, this.minHeight || 0)-this.list.shadowOffset-pad-5;         h = Math.min(h, space, this.maxHeight);         this.innerList.setHeight(h);         this.list.beginUpdate();         this.list.setHeight(h+pad);         this.list.alignTo(this.wrap, this.listAlign);         this.list.endUpdate();     },     // private     onEmptyResults : function(){         this.collapse();     },     /**      * Returns true if the dropdown list is expanded, else false.      */     isExpanded : function(){         return this.list && this.list.isVisible();     },     /**      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.      * @param {String} value The data value of the item to select      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the      * selected item if it is not currently in view (defaults to true)      * @return {Boolean} True if the value matched an item in the list, else false      */     selectByValue : function(v, scrollIntoView){         if(!Ext.isEmpty(v, true)){             var r = this.findRecord(this.valueField || this.displayField, v);             if(r){                 this.select(this.store.indexOf(r), scrollIntoView);                 return true;             }         }         return false;     },     /**      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.      * @param {Number} index The zero-based index of the list item to select      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the      * selected item if it is not currently in view (defaults to true)      */     select : function(index, scrollIntoView){         this.selectedIndex = index;         this.view.select(index);         if(scrollIntoView !== false){             var el = this.view.getNode(index);             if(el){                 this.innerList.scrollChildIntoView(el, false);             }         }     },     // private     selectNext : function(){         var ct = this.store.getCount();         if(ct > 0){             if(this.selectedIndex == -1){                 this.select(0);             }else if(this.selectedIndex < ct-1){                 this.select(this.selectedIndex+1);             }         }     },     // private     selectPrev : function(){         var ct = this.store.getCount();         if(ct > 0){             if(this.selectedIndex == -1){                 this.select(0);             }else if(this.selectedIndex !== 0){                 this.select(this.selectedIndex-1);             }         }     },     // private     onKeyUp : function(e){         var k = e.getKey();         if(this.editable !== false && (k == e.BACKSPACE || !e.isSpecialKey())){             this.lastKey = k;             this.dqTask.delay(this.queryDelay);         }         Ext.form.ComboBox.superclass.onKeyUp.call(this, e);     },     // private     validateBlur : function(){         return !this.list || !this.list.isVisible();     },     // private     initQuery : function(){         this.doQuery(this.getRawValue());     },     // private     beforeBlur : function(){         var val = this.getRawValue();         if(this.forceSelection){             if(val.length > 0 && val != this.emptyText){                this.el.dom.value = Ext.isDefined(this.lastSelectionText) ? this.lastSelectionText : '';                 this.applyEmptyText();             }else{                 this.clearValue();             }         }else{             var rec = this.findRecord(this.displayField, val);             if(rec){                 val = rec.get(this.valueField || this.displayField);             }             this.setValue(val);         }     },     /**      * Execute a query to filter the dropdown list.  Fires the {@link #beforequery} event prior to performing the      * query allowing the query action to be canceled if needed.      * @param {String} query The SQL query to execute      * @param {Boolean} forceAll <tt>true</tt> to force the query to execute even if there are currently fewer      * characters in the field than the minimum specified by the <tt>{@link #minChars}</tt> config option.  It      * also clears any filter previously saved in the current store (defaults to <tt>false</tt>)      */     doQuery : function(q, forceAll){         q = Ext.isEmpty(q) ? '' : q;         var qe = {             query: q,             forceAll: forceAll,             combo: this,             cancel:false         };         if(this.fireEvent('beforequery', qe)===false || qe.cancel){             return false;         }         q = qe.query;         forceAll = qe.forceAll;         if(forceAll === true || (q.length >= this.minChars)){             if(this.lastQuery !== q){                 this.lastQuery = q;                 if(this.mode == 'local'){                     this.selectedIndex = -1;                     if(forceAll){                         this.store.clearFilter();                     }else{                         this.store.filter(this.displayField, q);                     }                     this.onLoad();                 }else{                     this.store.baseParams[this.queryParam] = q;                     this.store.load({                         params: this.getParams(q)                     });                     this.expand();                 }             }else{                 this.selectedIndex = -1;                 this.onLoad();             }         }     },     // private     getParams : function(q){         var p = {};         //p[this.queryParam] = q;         if(this.pageSize){             p.start = 0;             p.limit = this.pageSize;         }         return p;     },     /**      * Hides the dropdown list if it is currently expanded. Fires the {@link #collapse} event on completion.      */     collapse : function(){         if(!this.isExpanded()){             return;         }         this.list.hide();         Ext.getDoc().un('mousewheel', this.collapseIf, this);         Ext.getDoc().un('mousedown', this.collapseIf, this);         this.fireEvent('collapse', this);     },     // private     collapseIf : function(e){         if(!e.within(this.wrap) && !e.within(this.list)){             this.collapse();         }     },     /**      * Expands the dropdown list if it is currently hidden. Fires the {@link #expand} event on completion.      */     expand : function(){         if(this.isExpanded() || !this.hasFocus){             return;         }         this.list.alignTo(this.wrap, this.listAlign);         this.list.show();         if(Ext.isGecko2){             this.innerList.setOverflow('auto'); // necessary for FF 2.0/Mac         }         Ext.getDoc().on({             scope: this,             mousewheel: this.collapseIf,             mousedown: this.collapseIf         });         this.fireEvent('expand', this);     },     /**      * @method onTriggerClick      * @hide      */     // private     // Implements the default empty TriggerField.onTriggerClick function     onTriggerClick : function(){         if(this.disabled){             return;         }         if(this.isExpanded()){             this.collapse();             this.el.focus();         }else {             this.onFocus({});             if(this.triggerAction == 'all') {                 this.doQuery(this.allQuery, true);             } else {                 this.doQuery(this.getRawValue());             }             this.el.focus();         }     }     /**      * @hide      * @method autoSize      */     /**      * @cfg {Boolean} grow @hide      */     /**      * @cfg {Number} growMin @hide      */     /**      * @cfg {Number} growMax @hide      */ }); Ext.reg('combo', Ext.form.ComboBox);/**  * @class Ext.form.Checkbox  * @extends Ext.form.Field  * Single checkbox field.  Can be used as a direct replacement for traditional checkbox fields.  * @constructor  * Creates a new Checkbox  * @param {Object} config Configuration options  * @xtype checkbox  */ Ext.form.Checkbox = Ext.extend(Ext.form.Field,  {     /**      * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)      */     focusClass : undefined,     /**      * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to 'x-form-field')      */     fieldClass : 'x-form-field',     /**      * @cfg {Boolean} checked <tt>true</tt> if the checkbox should render initially checked (defaults to <tt>false</tt>)      */     checked : false,     /**      * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to      * {tag: 'input', type: 'checkbox', autocomplete: 'off'})      */     defaultAutoCreate : { tag: 'input', type: 'checkbox', autocomplete: 'off'},     /**      * @cfg {String} boxLabel The text that appears beside the checkbox      */     /**      * @cfg {String} inputValue The value that should go into the generated input element's value attribute      */     /**      * @cfg {Function} handler A function called when the {@link #checked} value changes (can be used instead of       * handling the check event). The handler is passed the following parameters:      * <div class="mdetail-params"><ul>      * <li><b>checkbox</b> : Ext.form.Checkbox<div class="sub-desc">The Checkbox being toggled.</div></li>      * <li><b>checked</b> : Boolean<div class="sub-desc">The new checked state of the checkbox.</div></li>      * </ul></div>      */     /**      * @cfg {Object} scope An object to use as the scope ('this' reference) of the {@link #handler} function      * (defaults to this Checkbox).      */     // private     actionMode : 'wrap',      // private     initComponent : function(){         Ext.form.Checkbox.superclass.initComponent.call(this);         this.addEvents(             /**              * @event check              * Fires when the checkbox is checked or unchecked.              * @param {Ext.form.Checkbox} this This checkbox              * @param {Boolean} checked The new checked value              */             'check'         );     },     // private     onResize : function(){         Ext.form.Checkbox.superclass.onResize.apply(this, arguments);         if(!this.boxLabel && !this.fieldLabel){             this.el.alignTo(this.wrap, 'c-c');         }     },     // private     initEvents : function(){         Ext.form.Checkbox.superclass.initEvents.call(this);         this.mon(this.el, 'click', this.onClick, this);         this.mon(this.el, 'change', this.onClick, this);     }, // private     getResizeEl : function(){         return this.wrap;     },     // private     getPositionEl : function(){         return this.wrap;     },     /**      * @hide      * Overridden and disabled. The editor element does not support standard valid/invalid marking.      * @method      */     markInvalid : Ext.emptyFn,     /**      * @hide      * Overridden and disabled. The editor element does not support standard valid/invalid marking.      * @method      */     clearInvalid : Ext.emptyFn,     // private     onRender : function(ct, position){         Ext.form.Checkbox.superclass.onRender.call(this, ct, position);         if(this.inputValue !== undefined){             this.el.dom.value = this.inputValue;         }         this.wrap = this.el.wrap({cls: 'x-form-check-wrap'});         if(this.boxLabel){             this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});         }         if(this.checked){             this.setValue(true);         }else{             this.checked = this.el.dom.checked;         }     },     // private     onDestroy : function(){         Ext.destroy(this.wrap);         Ext.form.Checkbox.superclass.onDestroy.call(this);     },     // private     initValue : function() {         this.originalValue = this.getValue();     },     /**      * Returns the checked state of the checkbox.      * @return {Boolean} True if checked, else false      */     getValue : function(){         if(this.rendered){             return this.el.dom.checked;         }         return false;     }, // private     onClick : function(){         if(this.el.dom.checked != this.checked){             this.setValue(this.el.dom.checked);         }     },     /**      * Sets the checked state of the checkbox, fires the 'check' event, and calls a      * <code>{@link #handler}</code> (if configured).      * @param {Boolean/String} checked The following values will check the checkbox:      * <code>true, 'true', '1', or 'on'</code>. Any other value will uncheck the checkbox.      * @return {Ext.form.Field} this      */     setValue : function(v){         var checked = this.checked ;         this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');         if(this.rendered){             this.el.dom.checked = this.checked;             this.el.dom.defaultChecked = this.checked;         }         if(checked != this.checked){             this.fireEvent('check', this, this.checked);             if(this.handler){                 this.handler.call(this.scope || this, this, this.checked);             }         }         return this;     } }); Ext.reg('checkbox', Ext.form.Checkbox); /**  * @class Ext.form.CheckboxGroup  * @extends Ext.form.Field  * <p>A grouping container for {@link Ext.form.Checkbox} controls.</p>  * <p>Sample usage:</p>  * <pre><code> var myCheckboxGroup = new Ext.form.CheckboxGroup({     id:'myGroup',     xtype: 'checkboxgroup',     fieldLabel: 'Single Column',     itemCls: 'x-check-group-alt',     // Put all controls in a single column with width 100%     columns: 1,     items: [         {boxLabel: 'Item 1', name: 'cb-col-1'},         {boxLabel: 'Item 2', name: 'cb-col-2', checked: true},         {boxLabel: 'Item 3', name: 'cb-col-3'}     ] });  * </code></pre>  * @constructor  * Creates a new CheckboxGroup  * @param {Object} config Configuration options  * @xtype checkboxgroup  */ Ext.form.CheckboxGroup = Ext.extend(Ext.form.Field, {     /**      * @cfg {Array} items An Array of {@link Ext.form.Checkbox Checkbox}es or Checkbox config objects      * to arrange in the group.      */     /**      * @cfg {String/Number/Array} columns Specifies the number of columns to use when displaying grouped      * checkbox/radio controls using automatic layout.  This config can take several types of values:      * <ul><li><b>'auto'</b> : <p class="sub-desc">The controls will be rendered one per column on one row and the width      * of each column will be evenly distributed based on the width of the overall field container. This is the default.</p></li>      * <li><b>Number</b> : <p class="sub-desc">If you specific a number (e.g., 3) that number of columns will be       * created and the contained controls will be automatically distributed based on the value of {@link #vertical}.</p></li>      * <li><b>Array</b> : Object<p class="sub-desc">You can also specify an array of column widths, mixing integer      * (fixed width) and float (percentage width) values as needed (e.g., [100, .25, .75]). Any integer values will      * be rendered first, then any float values will be calculated as a percentage of the remaining space. Float      * values do not have to add up to 1 (100%) although if you want the controls to take up the entire field      * container you should do so.</p></li></ul>      */     columns : 'auto',     /**      * @cfg {Boolean} vertical True to distribute contained controls across columns, completely filling each column       * top to bottom before starting on the next column.  The number of controls in each column will be automatically      * calculated to keep columns as even as possible.  The default value is false, so that controls will be added      * to columns one at a time, completely filling each row left to right before starting on the next row.      */     vertical : false,     /**      * @cfg {Boolean} allowBlank False to validate that at least one item in the group is checked (defaults to true).      * If no items are selected at validation time, {@link @blankText} will be used as the error text.      */     allowBlank : true,     /**      * @cfg {String} blankText Error text to display if the {@link #allowBlank} validation fails (defaults to "You must       * select at least one item in this group")      */     blankText : "You must select at least one item in this group",          // private     defaultType : 'checkbox',          // private     groupCls : 'x-form-check-group',          // private     initComponent: function(){         this.addEvents(             /**              * @event change              * Fires when the state of a child checkbox changes.              * @param {Ext.form.CheckboxGroup} this              * @param {Array} checked An array containing the checked boxes.              */             'change'         );            Ext.form.CheckboxGroup.superclass.initComponent.call(this);     },          // private     onRender : function(ct, position){         if(!this.el){             var panelCfg = {                 cls: this.groupCls,                 layout: 'column',                 border: false,                 renderTo: ct             };             var colCfg = {                 defaultType: this.defaultType,                 layout: 'form',                 border: false,                 defaults: {                     hideLabel: true,                     anchor: '100%'                 }             };                          if(this.items[0].items){                                  // The container has standard ColumnLayout configs, so pass them in directly                                  Ext.apply(panelCfg, {                     layoutConfig: {columns: this.items.length},                     defaults: this.defaults,                     items: this.items                 });                 for(var i=0, len=this.items.length; i<len; i++){                     Ext.applyIf(this.items[i], colCfg);                 }                              }else{                                  // The container has field item configs, so we have to generate the column                 // panels first then move the items into the columns as needed.                                  var numCols, cols = [];                                  if(typeof this.columns == 'string'){ // 'auto' so create a col per item                     this.columns = this.items.length;                 }                 if(!Ext.isArray(this.columns)){                     var cs = [];                     for(var i=0; i<this.columns; i++){                         cs.push((100/this.columns)*.01); // distribute by even %                     }                     this.columns = cs;                 }                                  numCols = this.columns.length;                                  // Generate the column configs with the correct width setting                 for(var i=0; i<numCols; i++){                     var cc = Ext.apply({items:[]}, colCfg);                     cc[this.columns[i] <= 1 ? 'columnWidth' : 'width'] = this.columns[i];                     if(this.defaults){                         cc.defaults = Ext.apply(cc.defaults || {}, this.defaults)                     }                     cols.push(cc);                 };                                  // Distribute the original items into the columns                 if(this.vertical){                     var rows = Math.ceil(this.items.length / numCols), ri = 0;                     for(var i=0, len=this.items.length; i<len; i++){                         if(i>0 && i%rows==0){                             ri++;                         }                         if(this.items[i].fieldLabel){                             this.items[i].hideLabel = false;                         }                         cols[ri].items.push(this.items[i]);                     };                 }else{                     for(var i=0, len=this.items.length; i<len; i++){                         var ci = i % numCols;                         if(this.items[i].fieldLabel){                             this.items[i].hideLabel = false;                         }                         cols[ci].items.push(this.items[i]);                     };                 }                                  Ext.apply(panelCfg, {                     layoutConfig: {columns: numCols},                     items: cols                 });             }                          this.panel = new Ext.Panel(panelCfg);             this.panel.ownerCt = this;             this.el = this.panel.getEl();                          if(this.forId && this.itemCls){                 var l = this.el.up(this.itemCls).child('label', true);                 if(l){                     l.setAttribute('htmlFor', this.forId);                 }             }                          var fields = this.panel.findBy(function(c){                 return c.isFormField;             }, this);                          this.items = new Ext.util.MixedCollection();             this.items.addAll(fields);         }         Ext.form.CheckboxGroup.superclass.onRender.call(this, ct, position);     },          afterRender : function(){         Ext.form.CheckboxGroup.superclass.afterRender.call(this);         if(this.values){             this.setValue.apply(this, this.values);             delete this.values;         }         this.eachItem(function(item){             item.on('check', this.fireChecked, this);             item.inGroup = true;         });     },          // private     doLayout: function(){         //ugly method required to layout hidden items         if(this.rendered){             this.panel.forceLayout = this.ownerCt.forceLayout;             this.panel.doLayout();         }     },          // private     fireChecked: function(){         var arr = [];         this.eachItem(function(item){             if(item.checked){                 arr.push(item);             }         });         this.fireEvent('change', this, arr);     },          // private     validateValue : function(value){         if(!this.allowBlank){             var blank = true;             this.eachItem(function(f){                 if(f.checked){                     return (blank = false);                 }             });             if(blank){                 this.markInvalid(this.blankText);                 return false;             }         }         return true;     },          // private     onDisable : function(){         this.eachItem(function(item){             item.disable();         });     },     // private     onEnable : function(){         this.eachItem(function(item){             item.enable();         });     },          // private     doLayout: function(){         if(this.rendered){             this.panel.forceLayout = this.ownerCt.forceLayout;             this.panel.doLayout();         }     },          // private     onResize : function(w, h){         this.panel.setSize(w, h);         this.panel.doLayout();     },          // inherit docs from Field     reset : function(){         Ext.form.CheckboxGroup.superclass.reset.call(this);         this.eachItem(function(c){             if(c.reset){                 c.reset();             }         });     },          /**      * {@link Ext.form.Checkbox#setValue Set the value(s)} of an item or items      * in the group. Examples illustrating how this method may be called:      * <pre><code> // call with name and value myCheckboxGroup.setValue('cb-col-1', true); // call with an array of boolean values  myCheckboxGroup.setValue([true, false, false]); // call with an object literal specifying item:value pairs myCheckboxGroup.setValue({     'cb-col-2': false,     'cb-col-3': true }); // use comma separated string to set items with name to true (checked) myCheckboxGroup.setValue('cb-col-1,cb-col-3');      * </code></pre>      * See {@link Ext.form.Checkbox#setValue} for additional information.      * @param {Mixed} id The checkbox to check, or as described by example shown.      * @param {Boolean} value (optional) The value to set the item.      * @return {Ext.form.CheckboxGroup} this      */     setValue : function(id, value){         if(this.rendered){             if(arguments.length == 1){                 if(Ext.isArray(id)){                     //an array of boolean values                     Ext.each(id, function(val, idx){                         var item = this.items.itemAt(idx);                         if(item){                             item.setValue(val);                         }                     }, this);                 }else if(Ext.isObject(id)){                     //set of name/value pairs                     for(var i in id){                         var f = this.getBox(i);                         if(f){                             f.setValue(id[i]);                         }                     }                 }else{                     this.setValueForItem(id);                 }             }else{                 var f = this.getBox(id);                 if(f){                     f.setValue(value);                 }             }         }else{             this.values = arguments;         }         return this;     },          // private     onDestroy: function(){         Ext.destroy(this.panel);         Ext.form.CheckboxGroup.superclass.onDestroy.call(this);     },          setValueForItem : function(val){         val = String(val).split(',');         this.eachItem(function(item){             if(val.indexOf(item.inputValue)> -1){                 item.setValue(true);             }         });     },          // private     getBox : function(id){         var box = null;         this.eachItem(function(f){             if(id == f || f.dataIndex == id || f.id == id || f.getName() == id){                 box = f;                 return false;             }         });         return box;     },          /**      * Gets an array of the selected {@link Ext.form.Checkbox} in the group.      * @return {Array} An array of the selected checkboxes.      */     getValue : function(){         var out = [];         this.eachItem(function(item){             if(item.checked){                 out.push(item);             }         });         return out;     },          // private     eachItem: function(fn){         if(this.items && this.items.each){             this.items.each(fn, this);         }     },          /**      * @cfg {String} name      * @hide      */     /**      * @method initValue      * @hide      */     initValue : Ext.emptyFn,     /**      * @method getValue      * @hide      */     getValue : Ext.emptyFn,     /**      * @method getRawValue      * @hide      */     getRawValue : Ext.emptyFn,          /**      * @method setRawValue      * @hide      */     setRawValue : Ext.emptyFn      }); Ext.reg('checkboxgroup', Ext.form.CheckboxGroup); /**  * @class Ext.form.Radio  * @extends Ext.form.Checkbox  * Single radio field.  Same as Checkbox, but provided as a convenience for automatically setting the input type.  * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.  * @constructor  * Creates a new Radio  * @param {Object} config Configuration options  * @xtype radio  */ Ext.form.Radio = Ext.extend(Ext.form.Checkbox, {     inputType: 'radio',     /**      * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide      * @method      */     markInvalid : Ext.emptyFn,     /**      * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide      * @method      */     clearInvalid : Ext.emptyFn,     /**      * If this radio is part of a group, it will return the selected value      * @return {String}      */     getGroupValue : function(){      var p = this.el.up('form') || Ext.getBody();         var c = p.child('input[name='+this.el.dom.name+']:checked', true);         return c ? c.value : null;     },     // private     onClick : function(){      if(this.el.dom.checked != this.checked){ var els = this.getCheckEl().select('input[name=' + this.el.dom.name + ']'); els.each(function(el){ if(el.dom.id == this.id){ this.setValue(true); }else{ Ext.getCmp(el.dom.id).setValue(false); } }, this); }     },     /**      * Sets either the checked/unchecked status of this Radio, or, if a string value      * is passed, checks a sibling Radio of the same name whose value is the value specified.      * @param value {String/Boolean} Checked value, or the value of the sibling radio button to check.      * @return {Ext.form.Field} this      */     setValue : function(v){      if (typeof v == 'boolean') {             Ext.form.Radio.superclass.setValue.call(this, v);         } else {             var r = this.getCheckEl().child('input[name=' + this.el.dom.name + '][value=' + v + ']', true);             if(r){                 Ext.getCmp(r.id).setValue(true);             }         }         return this;     },          // private     getCheckEl: function(){         if(this.inGroup){             return this.el.up('.x-form-radio-group')         }         return this.el.up('form') || Ext.getBody();     } }); Ext.reg('radio', Ext.form.Radio); /**  * @class Ext.form.RadioGroup  * @extends Ext.form.CheckboxGroup  * A grouping container for {@link Ext.form.Radio} controls.  * @constructor  * Creates a new RadioGroup  * @param {Object} config Configuration options  * @xtype radiogroup  */ Ext.form.RadioGroup = Ext.extend(Ext.form.CheckboxGroup, {     /**      * @cfg {Boolean} allowBlank True to allow every item in the group to be blank (defaults to true).      * If allowBlank = false and no items are selected at validation time, {@link @blankText} will      * be used as the error text.      */     allowBlank : true,     /**      * @cfg {String} blankText Error text to display if the {@link #allowBlank} validation fails      * (defaults to 'You must select one item in this group')      */     blankText : 'You must select one item in this group',          // private     defaultType : 'radio',          // private     groupCls : 'x-form-radio-group',          /**      * @event change      * Fires when the state of a child radio changes.      * @param {Ext.form.RadioGroup} this      * @param {Ext.form.Radio} checked The checked radio      */          /**      * Gets the selected {@link Ext.form.Radio} in the group, if it exists.      * @return {Ext.form.Radio} The selected radio.      */     getValue : function(){         var out = null;         this.eachItem(function(item){             if(item.checked){                 out = item;                 return false;             }         });         return out;     },          /**      * Sets the checked radio in the group.      * @param {String/Ext.form.Radio} id The radio to check.      * @param {Boolean} value The value to set the radio.      * @return {Ext.form.RadioGroup} this      */     setValue : function(id, value){         if(this.rendered){             if(arguments.length > 1){                 var f = this.getBox(id);                 if(f){                     f.setValue(value);                     if(f.checked){                         this.eachItem(function(item){                             if (item !== f){                                 item.setValue(false);                             }                         });                     }                 }             }else{                 this.setValueForItem(id);             }         }else{             this.values = arguments;         }         return this;     },          // private     fireChecked : function(){         if(!this.checkTask){             this.checkTask = new Ext.util.DelayedTask(this.bufferChecked, this);         }         this.checkTask.delay(10);     },          // private     bufferChecked : function(){         var out = null;         this.eachItem(function(item){             if(item.checked){                 out = item;                 return false;             }         });         this.fireEvent('change', this, out);     },          onDestroy : function(){         if(this.checkTask){             this.checkTask.cancel();             this.checkTask = null;         }         Ext.form.RadioGroup.superclass.onDestroy.call(this);     } }); Ext.reg('radiogroup', Ext.form.RadioGroup); /**
  1018.  * @class Ext.form.Hidden
  1019.  * @extends Ext.form.Field
  1020.  * A basic hidden field for storing hidden values in forms that need to be passed in the form submit.
  1021.  * @constructor
  1022.  * Create a new Hidden field.
  1023.  * @param {Object} config Configuration options
  1024.  * @xtype hidden
  1025.  */
  1026. Ext.form.Hidden = Ext.extend(Ext.form.Field, {
  1027.     // private
  1028.     inputType : 'hidden',
  1029.     // private
  1030.     onRender : function(){
  1031.         Ext.form.Hidden.superclass.onRender.apply(this, arguments);
  1032.     },
  1033.     // private
  1034.     initEvents : function(){
  1035.         this.originalValue = this.getValue();
  1036.     },
  1037.     // These are all private overrides
  1038.     setSize : Ext.emptyFn,
  1039.     setWidth : Ext.emptyFn,
  1040.     setHeight : Ext.emptyFn,
  1041.     setPosition : Ext.emptyFn,
  1042.     setPagePosition : Ext.emptyFn,
  1043.     markInvalid : Ext.emptyFn,
  1044.     clearInvalid : Ext.emptyFn
  1045. });
  1046. Ext.reg('hidden', Ext.form.Hidden);/**  * @class Ext.form.BasicForm  * @extends Ext.util.Observable  * <p>Encapsulates the DOM &lt;form> element at the heart of the {@link Ext.form.FormPanel FormPanel} class, and provides  * input field management, validation, submission, and form loading services.</p>  * <p>By default, Ext Forms are submitted through Ajax, using an instance of {@link Ext.form.Action.Submit}.  * To enable normal browser submission of an Ext Form, use the {@link #standardSubmit} config option.</p>  * <p><b><u>File Uploads</u></b></p>  * <p>{@link #fileUpload File uploads} are not performed using Ajax submission, that  * is they are <b>not</b> performed using XMLHttpRequests. Instead the form is submitted in the standard  * manner with the DOM <tt>&lt;form></tt> element temporarily modified to have its  * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer  * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document  * but removed after the return data has been gathered.</p>  * <p>The server response is parsed by the browser to create the document for the IFRAME. If the  * server is using JSON to send the return object, then the  * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header  * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>  * <p>Characters which are significant to an HTML parser must be sent as HTML entities, so encode  * "&lt;" as "&amp;lt;", "&amp;" as "&amp;amp;" etc.</p>  * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object  * is created containing a <tt>responseText</tt> property in order to conform to the  * requirements of event handlers and callbacks.</p>  * <p>Be aware that file upload packets are sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form</a>  * and some server technologies (notably JEE) may require some custom processing in order to  * retrieve parameter names and parameter values from the packet content.</p>  * @constructor  * @param {Mixed} el The form element or its id  * @param {Object} config Configuration options  */ Ext.form.BasicForm = function(el, config){     Ext.apply(this, config);     if(Ext.isString(this.paramOrder)){         this.paramOrder = this.paramOrder.split(/[s,|]/);     }     /*      * @property items      * A {@link Ext.util.MixedCollection MixedCollection) containing all the Ext.form.Fields in this form.      * @type MixedCollection      */     this.items = new Ext.util.MixedCollection(false, function(o){         return o.itemId || o.id || (o.id = Ext.id());     });     this.addEvents(         /**          * @event beforeaction          * Fires before any action is performed. Return false to cancel the action.          * @param {Form} this          * @param {Action} action The {@link Ext.form.Action} to be performed          */         'beforeaction',         /**          * @event actionfailed          * Fires when an action fails.          * @param {Form} this          * @param {Action} action The {@link Ext.form.Action} that failed          */         'actionfailed',         /**          * @event actioncomplete          * Fires when an action is completed.          * @param {Form} this          * @param {Action} action The {@link Ext.form.Action} that completed          */         'actioncomplete'     );     if(el){         this.initEl(el);     }     Ext.form.BasicForm.superclass.constructor.call(this); }; Ext.extend(Ext.form.BasicForm, Ext.util.Observable, {     /**      * @cfg {String} method      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.      */     /**      * @cfg {DataReader} reader      * An Ext.data.DataReader (e.g. {@link Ext.data.XmlReader}) to be used to read      * data when executing 'load' actions. This is optional as there is built-in      * support for processing JSON.  For additional information on using an XMLReader      * see the example provided in examples/form/xml-form.html.      */     /**      * @cfg {DataReader} errorReader      * <p>An Ext.data.DataReader (e.g. {@link Ext.data.XmlReader}) to be used to      * read field error messages returned from 'submit' actions. This is optional      * as there is built-in support for processing JSON.</p>      * <p>The Records which provide messages for the invalid Fields must use the      * Field name (or id) as the Record ID, and must contain a field called 'msg'      * which contains the error message.</p>      * <p>The errorReader does not have to be a full-blown implementation of a      * DataReader. It simply needs to implement a <tt>read(xhr)</tt> function      * which returns an Array of Records in an object with the following      * structure:</p><pre><code> {     records: recordArray } </code></pre>      */     /**      * @cfg {String} url      * The URL to use for form actions if one isn't supplied in the      * <code>{@link #doAction doAction} options</code>.      */     /**      * @cfg {Boolean} fileUpload      * Set to true if this form is a file upload.      * <p>File uploads are not performed using normal 'Ajax' techniques, that is they are <b>not</b>      * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the      * DOM <tt>&lt;form></tt> element temporarily modified to have its      * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer      * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document      * but removed after the return data has been gathered.</p>      * <p>The server response is parsed by the browser to create the document for the IFRAME. If the      * server is using JSON to send the return object, then the      * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header      * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>      * <p>Characters which are significant to an HTML parser must be sent as HTML entities, so encode      * "&lt;" as "&amp;lt;", "&amp;" as "&amp;amp;" etc.</p>      * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object      * is created containing a <tt>responseText</tt> property in order to conform to the      * requirements of event handlers and callbacks.</p>      * <p>Be aware that file upload packets are sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form</a>      * and some server technologies (notably JEE) may require some custom processing in order to      * retrieve parameter names and parameter values from the packet content.</p>      */     /**      * @cfg {Object} baseParams      * <p>Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.</p>      * <p>Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode}.</p>      */     /**      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).      */     timeout: 30,     /**      * @cfg {Object} api (Optional) If specified load and submit actions will be handled      * with {@link Ext.form.Action.DirectLoad} and {@link Ext.form.Action.DirectSubmit}.      * Methods which have been imported by Ext.Direct can be specified here to load and submit      * forms.      * Such as the following:<pre><code> api: {     load: App.ss.MyProfile.load,     submit: App.ss.MyProfile.submit } </code></pre>      * <p>Load actions can use <code>{@link #paramOrder}</code> or <code>{@link #paramsAsHash}</code>      * to customize how the load method is invoked.      * Submit actions will always use a standard form submit. The formHandler configuration must      * be set on the associated server-side method which has been imported by Ext.Direct</p>      */     /**      * @cfg {Array/String} paramOrder <p>A list of params to be executed server side.      * Defaults to <tt>undefined</tt>. Only used for the <code>{@link #api}</code>      * <code>load</code> configuration.</p>      * <br><p>Specify the params in the order in which they must be executed on the      * server-side as either (1) an Array of String values, or (2) a String of params      * delimited by either whitespace, comma, or pipe. For example,      * any of the following would be acceptable:</p><pre><code> paramOrder: ['param1','param2','param3'] paramOrder: 'param1 param2 param3' paramOrder: 'param1,param2,param3' paramOrder: 'param1|param2|param'      </code></pre>      */     paramOrder: undefined,     /**      * @cfg {Boolean} paramsAsHash Only used for the <code>{@link #api}</code>      * <code>load</code> configuration. Send parameters as a collection of named      * arguments (defaults to <tt>false</tt>). Providing a      * <tt>{@link #paramOrder}</tt> nullifies this configuration.      */     paramsAsHash: false,     // private     activeAction : null,     /**      * @cfg {Boolean} trackResetOnLoad If set to <tt>true</tt>, {@link #reset}() resets to the last loaded      * or {@link #setValues}() data instead of when the form was first created.  Defaults to <tt>false</tt>.      */     trackResetOnLoad : false,     /**      * @cfg {Boolean} standardSubmit If set to true, standard HTML form submits are used instead of XHR (Ajax) style      * form submissions. (defaults to false)<br>      * <p><b>Note:</b> When using standardSubmit, the options to {@link #submit} are ignored because Ext's      * Ajax infrastracture is bypassed. To pass extra parameters (baseParams and params), you will need to      * create hidden fields within the form.</p>      * <p>The url config option is also bypassed, so set the action as well:</p>      * <pre><code> PANEL.getForm().getEl().dom.action = 'URL'      * </code></pre>      * An example encapsulating the above:      * <pre><code> new Ext.FormPanel({     standardSubmit: true,     baseParams: {         foo: 'bar'     },     url: 'myProcess.php',     items: [{         xtype: 'textfield',         name: 'userName'     }],     buttons: [{         text: 'Save',         handler: function(){             var O = this.ownerCt;             if (O.getForm().isValid()) {                 if (O.url)                     O.getForm().getEl().dom.action = O.url;                 if (O.baseParams) {                     for (i in O.baseParams) {                         O.add({                             xtype: 'hidden',                             name: i,                             value: O.baseParams[i]                         })                     }                     O.doLayout();                 }                 O.getForm().submit();             }         }     }] });      * </code></pre>      */     /**      * By default wait messages are displayed with Ext.MessageBox.wait. You can target a specific      * element by passing it or its id or mask the form itself by passing in true.      * @type Mixed      * @property waitMsgTarget      */     // private     initEl : function(el){         this.el = Ext.get(el);         this.id = this.el.id || Ext.id();         if(!this.standardSubmit){             this.el.on('submit', this.onSubmit, this);         }         this.el.addClass('x-form');     },     /**      * Get the HTML form Element      * @return Ext.Element      */     getEl: function(){         return this.el;     },     // private     onSubmit : function(e){         e.stopEvent();     },     // private     destroy: function() {         this.items.each(function(f){             Ext.destroy(f);         });         if(this.el){             this.el.removeAllListeners();             this.el.remove();         }         this.purgeListeners();     },     /**      * Returns true if client-side validation on the form is successful.      * @return Boolean      */     isValid : function(){         var valid = true;         this.items.each(function(f){            if(!f.validate()){                valid = false;            }         });         return valid;     },     /**      * <p>Returns true if any fields in this form have changed from their original values.</p>      * <p>Note that if this BasicForm was configured with {@link #trackResetOnLoad} then the      * Fields' <i>original values</i> are updated when the values are loaded by {@link #setValues}      * or {@link #loadRecord}.</p>      * @return Boolean      */     isDirty : function(){         var dirty = false;         this.items.each(function(f){            if(f.isDirty()){                dirty = true;                return false;            }         });         return dirty;     },     /**      * Performs a predefined action ({@link Ext.form.Action.Submit} or      * {@link Ext.form.Action.Load}) or a custom extension of {@link Ext.form.Action}      * to perform application-specific processing.      * @param {String/Object} actionName The name of the predefined action type,      * or instance of {@link Ext.form.Action} to perform.      * @param {Object} options (optional) The options to pass to the {@link Ext.form.Action}.      * All of the config options listed below are supported by both the      * {@link Ext.form.Action.Submit submit} and {@link Ext.form.Action.Load load}      * actions unless otherwise noted (custom actions could also accept      * other config options):<ul>      *      * <li><b>url</b> : String<div class="sub-desc">The url for the action (defaults      * to the form's {@link #url}.)</div></li>      *      * <li><b>method</b> : String<div class="sub-desc">The form method to use (defaults      * to the form's method, or POST if not defined)</div></li>      *      * <li><b>params</b> : String/Object<div class="sub-desc"><p>The params to pass      * (defaults to the form's baseParams, or none if not defined)</p>      * <p>Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode}.</p></div></li>      *      * <li><b>headers</b> : Object<div class="sub-desc">Request headers to set for the action      * (defaults to the form's default headers)</div></li>      *      * <li><b>success</b> : Function<div class="sub-desc">The callback that will      * be invoked after a successful response (see top of      * {@link Ext.form.Action.Submit submit} and {@link Ext.form.Action.Load load}      * for a description of what constitutes a successful response).      * The function is passed the following parameters:<ul>      * <li><tt>form</tt> : Ext.form.BasicForm<div class="sub-desc">The form that requested the action</div></li>      * <li><tt>action</tt> : The {@link Ext.form.Action Action} object which performed the operation.      * <div class="sub-desc">The action object contains these properties of interest:<ul>      * <li><tt>{@link Ext.form.Action#response response}</tt></li>      * <li><tt>{@link Ext.form.Action#result result}</tt> : interrogate for custom postprocessing</li>      * <li><tt>{@link Ext.form.Action#type type}</tt></li>      * </ul></div></li></ul></div></li>      *      * <li><b>failure</b> : Function<div class="sub-desc">The callback that will be invoked after a      * failed transaction attempt. The function is passed the following parameters:<ul>      * <li><tt>form</tt> : The {@link Ext.form.BasicForm} that requested the action.</li>      * <li><tt>action</tt> : The {@link Ext.form.Action Action} object which performed the operation.      * <div class="sub-desc">The action object contains these properties of interest:<ul>      * <li><tt>{@link Ext.form.Action#failureType failureType}</tt></li>      * <li><tt>{@link Ext.form.Action#response response}</tt></li>      * <li><tt>{@link Ext.form.Action#result result}</tt> : interrogate for custom postprocessing</li>      * <li><tt>{@link Ext.form.Action#type type}</tt></li>      * </ul></div></li></ul></div></li>      *      * <li><b>scope</b> : Object<div class="sub-desc">The scope in which to call the      * callback functions (The <tt>this</tt> reference for the callback functions).</div></li>      *      * <li><b>clientValidation</b> : Boolean<div class="sub-desc">Submit Action only.      * Determines whether a Form's fields are validated in a final call to      * {@link Ext.form.BasicForm#isValid isValid} prior to submission. Set to <tt>false</tt>      * to prevent this. If undefined, pre-submission field validation is performed.</div></li></ul>      *      * @return {BasicForm} this      */     doAction : function(action, options){         if(Ext.isString(action)){             action = new Ext.form.Action.ACTION_TYPES[action](this, options);         }         if(this.fireEvent('beforeaction', this, action) !== false){             this.beforeAction(action);             action.run.defer(100, action);         }         return this;     },     /**      * Shortcut to {@link #doAction do} a {@link Ext.form.Action.Submit submit action}.      * @param {Object} options The options to pass to the action (see {@link #doAction} for details).<br>      * <p><b>Note:</b> this is ignored when using the {@link #standardSubmit} option.</p>      * <p>The following code:</p><pre><code> myFormPanel.getForm().submit({     clientValidation: true,     url: 'updateConsignment.php',     params: {         newStatus: 'delivered'     },     success: function(form, action) {        Ext.Msg.alert('Success', action.result.msg);     },     failure: function(form, action) {         switch (action.failureType) {             case Ext.form.Action.CLIENT_INVALID:                 Ext.Msg.alert('Failure', 'Form fields may not be submitted with invalid values');                 break;             case Ext.form.Action.CONNECT_FAILURE:                 Ext.Msg.alert('Failure', 'Ajax communication failed');                 break;             case Ext.form.Action.SERVER_INVALID:                Ext.Msg.alert('Failure', action.result.msg);        }     } }); </code></pre>      * would process the following server response for a successful submission:<pre><code> {     "success":true, // note this is Boolean, not string     "msg":"Consignment updated" } </code></pre>      * and the following server response for a failed submission:<pre><code> {     "success":false, // note this is Boolean, not string     "msg":"You do not have permission to perform this operation" } </code></pre>      * @return {BasicForm} this      */     submit : function(options){         if(this.standardSubmit){             var v = this.isValid();             if(v){                 this.el.dom.submit();             }             return v;         }         var submitAction = String.format('{0}submit', this.api ? 'direct' : '');         this.doAction(submitAction, options);         return this;     },     /**      * Shortcut to {@link #doAction do} a {@link Ext.form.Action.Load load action}.      * @param {Object} options The options to pass to the action (see {@link #doAction} for details)      * @return {BasicForm} this      */     load : function(options){         var loadAction = String.format('{0}load', this.api ? 'direct' : '');         this.doAction(loadAction, options);         return this;     },     /**      * Persists the values in this form into the passed {@link Ext.data.Record} object in a beginEdit/endEdit block.      * @param {Record} record The record to edit      * @return {BasicForm} this      */     updateRecord : function(record){         record.beginEdit();         var fs = record.fields;         fs.each(function(f){             var field = this.findField(f.name);             if(field){                 record.set(f.name, field.getValue());             }         }, this);         record.endEdit();         return this;     },     /**      * Loads an {@link Ext.data.Record} into this form by calling {@link #setValues} with the      * {@link Ext.data.Record#data record data}.      * See also {@link #trackResetOnLoad}.      * @param {Record} record The record to load      * @return {BasicForm} this      */     loadRecord : function(record){         this.setValues(record.data);         return this;     },     // private     beforeAction : function(action){         var o = action.options;         if(o.waitMsg){             if(this.waitMsgTarget === true){                 this.el.mask(o.waitMsg, 'x-mask-loading');             }else if(this.waitMsgTarget){                 this.waitMsgTarget = Ext.get(this.waitMsgTarget);                 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');             }else{                 Ext.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');             }         }     },     // private     afterAction : function(action, success){         this.activeAction = null;         var o = action.options;         if(o.waitMsg){             if(this.waitMsgTarget === true){                 this.el.unmask();             }else if(this.waitMsgTarget){                 this.waitMsgTarget.unmask();             }else{                 Ext.MessageBox.updateProgress(1);                 Ext.MessageBox.hide();             }         }         if(success){             if(o.reset){                 this.reset();             }             Ext.callback(o.success, o.scope, [this, action]);             this.fireEvent('actioncomplete', this, action);         }else{             Ext.callback(o.failure, o.scope, [this, action]);             this.fireEvent('actionfailed', this, action);         }     },     /**      * Find a {@link Ext.form.Field} in this form.      * @param {String} id The value to search for (specify either a {@link Ext.Component#id id},      * {@link Ext.grid.Column#dataIndex dataIndex}, {@link Ext.form.Field#getName name or hiddenName}).      * @return Field      */     findField : function(id){         var field = this.items.get(id);         if(!Ext.isObject(field)){             this.items.each(function(f){                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){                     field = f;                     return false;                 }             });         }         return field || null;     },     /**      * Mark fields in this form invalid in bulk.      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}      * @return {BasicForm} this      */     markInvalid : function(errors){         if(Ext.isArray(errors)){             for(var i = 0, len = errors.length; i < len; i++){                 var fieldError = errors[i];                 var f = this.findField(fieldError.id);                 if(f){                     f.markInvalid(fieldError.msg);                 }             }         }else{             var field, id;             for(id in errors){                 if(!Ext.isFunction(errors[id]) && (field = this.findField(id))){                     field.markInvalid(errors[id]);                 }             }         }         return this;     },     /**      * Set values for fields in this form in bulk.      * @param {Array/Object} values Either an array in the form:<pre><code> [{id:'clientName', value:'Fred. Olsen Lines'},  {id:'portOfLoading', value:'FXT'},  {id:'portOfDischarge', value:'OSL'} ]</code></pre>      * or an object hash of the form:<pre><code> {     clientName: 'Fred. Olsen Lines',     portOfLoading: 'FXT',     portOfDischarge: 'OSL' }</code></pre>      * @return {BasicForm} this      */     setValues : function(values){         if(Ext.isArray(values)){ // array of objects             for(var i = 0, len = values.length; i < len; i++){                 var v = values[i];                 var f = this.findField(v.id);                 if(f){                     f.setValue(v.value);                     if(this.trackResetOnLoad){                         f.originalValue = f.getValue();                     }                 }             }         }else{ // object hash             var field, id;             for(id in values){                 if(!Ext.isFunction(values[id]) && (field = this.findField(id))){                     field.setValue(values[id]);                     if(this.trackResetOnLoad){                         field.originalValue = field.getValue();                     }                 }             }         }         return this;     },     /**      * <p>Returns the fields in this form as an object with key/value pairs as they would be submitted using a standard form submit.      * If multiple fields exist with the same name they are returned as an array.</p>      * <p><b>Note:</b> The values are collected from all enabled HTML input elements within the form, <u>not</u> from      * the Ext Field objects. This means that all returned values are Strings (or Arrays of Strings) and that the      * value can potentially be the emptyText of a field.</p>      * @param {Boolean} asString (optional) Pass true to return the values as a string. (defaults to false, returning an Object)      * @return {String/Object}      */     getValues : function(asString){         var fs = Ext.lib.Ajax.serializeForm(this.el.dom);         if(asString === true){             return fs;         }         return Ext.urlDecode(fs);     },     getFieldValues : function(){         var o = {};         this.items.each(function(f){            o[f.getName()] = f.getValue();         });         return o;     },     /**      * Clears all invalid messages in this form.      * @return {BasicForm} this      */     clearInvalid : function(){         this.items.each(function(f){            f.clearInvalid();         });         return this;     },     /**      * Resets this form.      * @return {BasicForm} this      */     reset : function(){         this.items.each(function(f){             f.reset();         });         return this;     },     /**      * Add Ext.form Components to this form's Collection. This does not result in rendering of      * the passed Component, it just enables the form to validate Fields, and distribute values to      * Fields.      * <p><b>You will not usually call this function. In order to be rendered, a Field must be added      * to a {@link Ext.Container Container}, usually an {@link Ext.form.FormPanel FormPanel}.      * The FormPanel to which the field is added takes care of adding the Field to the BasicForm's      * collection.</b></p>      * @param {Field} field1      * @param {Field} field2 (optional)      * @param {Field} etc (optional)      * @return {BasicForm} this      */     add : function(){         this.items.addAll(Array.prototype.slice.call(arguments, 0));         return this;     },     /**      * Removes a field from the items collection (does NOT remove its markup).      * @param {Field} field      * @return {BasicForm} this      */     remove : function(field){         this.items.remove(field);         return this;     },     /**      * Iterates through the {@link Ext.form.Field Field}s which have been {@link #add add}ed to this BasicForm,      * checks them for an id attribute, and calls {@link Ext.form.Field#applyToMarkup} on the existing dom element with that id.      * @return {BasicForm} this      */     render : function(){         this.items.each(function(f){             if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists                 f.applyToMarkup(f.id);             }         });         return this;     },     /**      * Calls {@link Ext#apply} for all fields in this form with the passed object.      * @param {Object} values      * @return {BasicForm} this      */     applyToFields : function(o){         this.items.each(function(f){            Ext.apply(f, o);         });         return this;     },     /**      * Calls {@link Ext#applyIf} for all field in this form with the passed object.      * @param {Object} values      * @return {BasicForm} this      */     applyIfToFields : function(o){         this.items.each(function(f){            Ext.applyIf(f, o);         });         return this;     },     callFieldMethod : function(fnName, args){         args = args || [];         this.items.each(function(f){             if(Ext.isFunction(f[fnName])){                 f[fnName].apply(f, args);             }         });         return this;     } }); // back compat Ext.BasicForm = Ext.form.BasicForm;/**  * @class Ext.form.FormPanel  * @extends Ext.Panel  * <p>Standard form container.</p>  *   * <p><b><u>Layout</u></b></p>  * <p>By default, FormPanel is configured with <tt>layout:'form'</tt> to use an {@link Ext.layout.FormLayout}  * layout manager, which styles and renders fields and labels correctly. When nesting additional Containers  * within a FormPanel, you should ensure that any descendant Containers which host input Fields use the  * {@link Ext.layout.FormLayout} layout manager.</p>  *   * <p><b><u>BasicForm</u></b></p>  * <p>Although <b>not listed</b> as configuration options of FormPanel, the FormPanel class accepts all  * of the config options required to configure its internal {@link Ext.form.BasicForm} for:  * <div class="mdetail-params"><ul>  * <li>{@link Ext.form.BasicForm#fileUpload file uploads}</li>  * <li>functionality for {@link Ext.form.BasicForm#doAction loading, validating and submitting} the form</li>  * </ul></div>  *    * <p><b>Note</b>: If subclassing FormPanel, any configuration options for the BasicForm must be applied to  * the <tt><b>initialConfig</b></tt> property of the FormPanel. Applying {@link Ext.form.BasicForm BasicForm}  * configuration settings to <b><tt>this</tt></b> will <b>not</b> affect the BasicForm's configuration.</p>  *   * <p><b><u>Form Validation</u></b></p>  * <p>For information on form validation see the following:</p>  * <div class="mdetail-params"><ul>  * <li>{@link Ext.form.TextField}</li>  * <li>{@link Ext.form.VTypes}</li>  * <li>{@link Ext.form.BasicForm#doAction BasicForm.doAction <b>clientValidation</b> notes}</li>  * <li><tt>{@link Ext.form.FormPanel#monitorValid monitorValid}</tt></li>  * </ul></div>  *   * <p><b><u>Form Submission</u></b></p>  * <p>By default, Ext Forms are submitted through Ajax, using {@link Ext.form.Action}. To enable normal browser  * submission of the {@link Ext.form.BasicForm BasicForm} contained in this FormPanel, see the  * <tt><b>{@link Ext.form.BasicForm#standardSubmit standardSubmit}</b></tt> option.</p>  *   * @constructor  * @param {Object} config Configuration options  * @xtype form  */ Ext.FormPanel = Ext.extend(Ext.Panel, { /**  * @cfg {String} formId (optional) The id of the FORM tag (defaults to an auto-generated id).  */     /**      * @cfg {Boolean} hideLabels      * <p><tt>true</tt> to hide field labels by default (sets <tt>display:none</tt>). Defaults to      * <tt>false</tt>.</p>      * <p>Also see {@link Ext.Component}.<tt>{@link Ext.Component#hideLabel hideLabel}</tt>.      */     /**      * @cfg {Number} labelPad      * The default padding in pixels for field labels (defaults to <tt>5</tt>). <tt>labelPad</tt> only      * applies if <tt>{@link #labelWidth}</tt> is also specified, otherwise it will be ignored.      */     /**      * @cfg {String} labelSeparator      * See {@link Ext.Component}.<tt>{@link Ext.Component#labelSeparator labelSeparator}</tt>      */     /**      * @cfg {Number} labelWidth The width of labels in pixels. This property cascades to child containers      * and can be overridden on any child container (e.g., a fieldset can specify a different <tt>labelWidth</tt>      * for its fields) (defaults to <tt>100</tt>).      */     /**      * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.      */     /**      * @cfg {Array} buttons      * An array of {@link Ext.Button}s or {@link Ext.Button} configs used to add buttons to the footer of this FormPanel.<br>      * <p>Buttons in the footer of a FormPanel may be configured with the option <tt>formBind: true</tt>. This causes      * the form's {@link #monitorValid valid state monitor task} to enable/disable those Buttons depending on      * the form's valid/invalid state.</p>      */     /**      * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to <tt>75</tt>).      */     minButtonWidth : 75,     /**      * @cfg {String} labelAlign The label alignment value used for the <tt>text-align</tt> specification      * for the <b>container</b>. Valid values are <tt>"left</tt>", <tt>"top"</tt> or <tt>"right"</tt>      * (defaults to <tt>"left"</tt>). This property cascades to child <b>containers</b> and can be      * overridden on any child <b>container</b> (e.g., a fieldset can specify a different <tt>labelAlign</tt>      * for its fields).      */     labelAlign : 'left',     /**      * @cfg {Boolean} monitorValid If <tt>true</tt>, the form monitors its valid state <b>client-side</b> and      * regularly fires the {@link #clientvalidation} event passing that state.<br>      * <p>When monitoring valid state, the FormPanel enables/disables any of its configured      * {@link #buttons} which have been configured with <code>formBind: true</code> depending      * on whether the {@link Ext.form.BasicForm#isValid form is valid} or not. Defaults to <tt>false</tt></p>      */     monitorValid : false,     /**      * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)      */     monitorPoll : 200,     /**      * @cfg {String} layout Defaults to <tt>'form'</tt>.  Normally this configuration property should not be altered.       * For additional details see {@link Ext.layout.FormLayout} and {@link Ext.Container#layout Ext.Container.layout}.      */     layout : 'form',     // private     initComponent : function(){         this.form = this.createForm();         Ext.FormPanel.superclass.initComponent.call(this);         this.bodyCfg = {             tag: 'form',             cls: this.baseCls + '-body',             method : this.method || 'POST',             id : this.formId || Ext.id()         };         if(this.fileUpload) {             this.bodyCfg.enctype = 'multipart/form-data';         }         this.initItems();                  this.addEvents(             /**              * @event clientvalidation              * If the monitorValid config option is true, this event fires repetitively to notify of valid state              * @param {Ext.form.FormPanel} this              * @param {Boolean} valid true if the form has passed client-side validation              */             'clientvalidation'         );         this.relayEvents(this.form, ['beforeaction', 'actionfailed', 'actioncomplete']);     },     // private     createForm : function(){         var config = Ext.applyIf({listeners: {}}, this.initialConfig);         return new Ext.form.BasicForm(null, config);     },     // private     initFields : function(){         var f = this.form;         var formPanel = this;         var fn = function(c){             if(formPanel.isField(c)){                 f.add(c);             }if(c.isFieldWrap){                 Ext.applyIf(c, {                     labelAlign: c.ownerCt.labelAlign,                     labelWidth: c.ownerCt.labelWidth,                     itemCls: c.ownerCt.itemCls                 });                 f.add(c.field);             }else if(c.doLayout && c != formPanel){                 Ext.applyIf(c, {                     labelAlign: c.ownerCt.labelAlign,                     labelWidth: c.ownerCt.labelWidth,                     itemCls: c.ownerCt.itemCls                 });                 //each check required for check/radio groups.                 if(c.items && c.items.each){                     c.items.each(fn, this);                 }             }         };         this.items.each(fn, this);     },     // private     getLayoutTarget : function(){         return this.form.el;     },     /**      * Provides access to the {@link Ext.form.BasicForm Form} which this Panel contains.      * @return {Ext.form.BasicForm} The {@link Ext.form.BasicForm Form} which this Panel contains.      */     getForm : function(){         return this.form;     },     // private     onRender : function(ct, position){         this.initFields();         Ext.FormPanel.superclass.onRender.call(this, ct, position);         this.form.initEl(this.body);     },          // private     beforeDestroy : function(){         this.stopMonitoring();         Ext.FormPanel.superclass.beforeDestroy.call(this);         /*          * Clear the items here to prevent them being destroyed again.          * Don't move this behaviour to BasicForm because it can be used          * on it's own.          */         this.form.items.clear();         Ext.destroy(this.form);     }, // Determine if a Component is usable as a form Field.     isField : function(c) {         return !!c.setValue && !!c.getValue && !!c.markInvalid && !!c.clearInvalid;     },     // private     initEvents : function(){         Ext.FormPanel.superclass.initEvents.call(this);         this.on('remove', this.onRemove, this);         this.on('add', this.onAdd, this);         if(this.monitorValid){ // initialize after render             this.startMonitoring();         }     },          // private     onAdd : function(ct, c) { // If a single form Field, add it         if (this.isField(c)) {             this.form.add(c); // If a Container, add any Fields it might contain         } else if (c.findBy) {             Ext.applyIf(c, {                 labelAlign: c.ownerCt.labelAlign,                 labelWidth: c.ownerCt.labelWidth,                 itemCls: c.ownerCt.itemCls             });             this.form.add.apply(this.form, c.findBy(this.isField));         }     },     // private     onRemove : function(ct, c) { // If a single form Field, remove it         if (this.isField(c)) {             Ext.destroy(c.container.up('.x-form-item'));          this.form.remove(c); // If a Container, remove any Fields it might contain         } else if (c.findByType) {             Ext.each(c.findBy(this.isField), this.form.remove, this.form);         }     },     /**      * Starts monitoring of the valid state of this form. Usually this is done by passing the config      * option "monitorValid"      */     startMonitoring : function(){         if(!this.validTask){             this.validTask = new Ext.util.TaskRunner();             this.validTask.start({                 run : this.bindHandler,                 interval : this.monitorPoll || 200,                 scope: this             });         }     },     /**      * Stops monitoring of the valid state of this form      */     stopMonitoring : function(){         if(this.validTask){             this.validTask.stopAll();             this.validTask = null;         }     },     /**      * This is a proxy for the underlying BasicForm's {@link Ext.form.BasicForm#load} call.      * @param {Object} options The options to pass to the action (see {@link Ext.form.BasicForm#doAction} for details)      */     load : function(){         this.form.load.apply(this.form, arguments);       },     // private     onDisable : function(){         Ext.FormPanel.superclass.onDisable.call(this);         if(this.form){             this.form.items.each(function(){                  this.disable();             });         }     },     // private     onEnable : function(){         Ext.FormPanel.superclass.onEnable.call(this);         if(this.form){             this.form.items.each(function(){                  this.enable();             });         }     },     // private     bindHandler : function(){         var valid = true;         this.form.items.each(function(f){             if(!f.isValid(true)){                 valid = false;                 return false;             }         });         if(this.fbar){             var fitems = this.fbar.items.items;             for(var i = 0, len = fitems.length; i < len; i++){                 var btn = fitems[i];                 if(btn.formBind === true && btn.disabled === valid){                     btn.setDisabled(!valid);                 }             }         }         this.fireEvent('clientvalidation', this, valid);     } }); Ext.reg('form', Ext.FormPanel); Ext.form.FormPanel = Ext.FormPanel; /**
  1047.  * @class Ext.form.FieldSet
  1048.  * @extends Ext.Panel
  1049.  * Standard container used for grouping items within a {@link Ext.form.FormPanel form}.
  1050.  * <pre><code>
  1051. var form = new Ext.FormPanel({
  1052.     title: 'Simple Form with FieldSets',
  1053.     labelWidth: 75, // label settings here cascade unless overridden
  1054.     url: 'save-form.php',
  1055.     frame:true,
  1056.     bodyStyle:'padding:5px 5px 0',
  1057.     width: 700,
  1058.     renderTo: document.body,
  1059.     layout:'column', // arrange items in columns
  1060.     defaults: {      // defaults applied to items
  1061.         layout: 'form',
  1062.         border: false,
  1063.         bodyStyle: 'padding:4px'
  1064.     },
  1065.     items: [{
  1066.         // Fieldset in Column 1
  1067.         xtype:'fieldset',
  1068.         columnWidth: 0.5,
  1069.         title: 'Fieldset 1',
  1070.         collapsible: true,
  1071.         autoHeight:true,
  1072.         defaults: {
  1073.             anchor: '-20' // leave room for error icon
  1074.         },
  1075.         defaultType: 'textfield',
  1076.         items :[{
  1077.                 fieldLabel: 'Field 1'
  1078.             }, {
  1079.                 fieldLabel: 'Field 2'
  1080.             }, {
  1081.                 fieldLabel: 'Field 3'
  1082.             }
  1083.         ]
  1084.     },{
  1085.         // Fieldset in Column 2 - Panel inside
  1086.         xtype:'fieldset',
  1087.         title: 'Show Panel', // title, header, or checkboxToggle creates fieldset header
  1088.         autoHeight:true,
  1089.         columnWidth: 0.5,
  1090.         checkboxToggle: true,
  1091.         collapsed: true, // fieldset initially collapsed
  1092.         layout:'anchor',
  1093.         items :[{
  1094.             xtype: 'panel',
  1095.             anchor: '100%',
  1096.             title: 'Panel inside a fieldset',
  1097.             frame: true,
  1098.             height: 100
  1099.         }]
  1100.     }]
  1101. });
  1102.  * </code></pre>
  1103.  * @constructor
  1104.  * @param {Object} config Configuration options
  1105.  * @xtype fieldset
  1106.  */
  1107. Ext.form.FieldSet = Ext.extend(Ext.Panel, {
  1108.     /**
  1109.      * @cfg {Mixed} checkboxToggle <tt>true</tt> to render a checkbox into the fieldset frame just
  1110.      * in front of the legend to expand/collapse the fieldset when the checkbox is toggled. (defaults
  1111.      * to <tt>false</tt>).
  1112.      * <p>A {@link Ext.DomHelper DomHelper} element spec may also be specified to create the checkbox.
  1113.      * If <tt>true</tt> is specified, the default DomHelper config object used to create the element
  1114.      * is:</p><pre><code>
  1115.      * {tag: 'input', type: 'checkbox', name: this.checkboxName || this.id+'-checkbox'}
  1116.      * </code></pre>   
  1117.      */
  1118.     /**
  1119.      * @cfg {String} checkboxName The name to assign to the fieldset's checkbox if <tt>{@link #checkboxToggle} = true</tt>
  1120.      * (defaults to <tt>'[checkbox id]-checkbox'</tt>).
  1121.      */
  1122.     /**
  1123.      * @cfg {Boolean} collapsible
  1124.      * <tt>true</tt> to make the fieldset collapsible and have the expand/collapse toggle button automatically
  1125.      * rendered into the legend element, <tt>false</tt> to keep the fieldset statically sized with no collapse
  1126.      * button (defaults to <tt>false</tt>). Another option is to configure <tt>{@link #checkboxToggle}</tt>.
  1127.      */
  1128.     /**
  1129.      * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
  1130.      */
  1131.     /**
  1132.      * @cfg {String} itemCls A css class to apply to the <tt>x-form-item</tt> of fields (see 
  1133.      * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl} for details).
  1134.      * This property cascades to child containers.
  1135.      */
  1136.     /**
  1137.      * @cfg {String} baseCls The base CSS class applied to the fieldset (defaults to <tt>'x-fieldset'</tt>).
  1138.      */
  1139.     baseCls : 'x-fieldset',
  1140.     /**
  1141.      * @cfg {String} layout The {@link Ext.Container#layout} to use inside the fieldset (defaults to <tt>'form'</tt>).
  1142.      */
  1143.     layout : 'form',
  1144.     /**
  1145.      * @cfg {Boolean} animCollapse
  1146.      * <tt>true</tt> to animate the transition when the panel is collapsed, <tt>false</tt> to skip the
  1147.      * animation (defaults to <tt>false</tt>).
  1148.      */
  1149.     animCollapse : false,
  1150.     // private
  1151.     onRender : function(ct, position){
  1152.         if(!this.el){
  1153.             this.el = document.createElement('fieldset');
  1154.             this.el.id = this.id;
  1155.             if (this.title || this.header || this.checkboxToggle) {
  1156.                 this.el.appendChild(document.createElement('legend')).className = 'x-fieldset-header';
  1157.             }
  1158.         }
  1159.         Ext.form.FieldSet.superclass.onRender.call(this, ct, position);
  1160.         if(this.checkboxToggle){
  1161.             var o = typeof this.checkboxToggle == 'object' ?
  1162.                     this.checkboxToggle :
  1163.                     {tag: 'input', type: 'checkbox', name: this.checkboxName || this.id+'-checkbox'};
  1164.             this.checkbox = this.header.insertFirst(o);
  1165.             this.checkbox.dom.checked = !this.collapsed;
  1166.             this.mon(this.checkbox, 'click', this.onCheckClick, this);
  1167.         }
  1168.     },
  1169.     // private
  1170.     onCollapse : function(doAnim, animArg){
  1171.         if(this.checkbox){
  1172.             this.checkbox.dom.checked = false;
  1173.         }
  1174.         Ext.form.FieldSet.superclass.onCollapse.call(this, doAnim, animArg);
  1175.     },
  1176.     // private
  1177.     onExpand : function(doAnim, animArg){
  1178.         if(this.checkbox){
  1179.             this.checkbox.dom.checked = true;
  1180.         }
  1181.         Ext.form.FieldSet.superclass.onExpand.call(this, doAnim, animArg);
  1182.     },
  1183.     /**
  1184.      * This function is called by the fieldset's checkbox when it is toggled (only applies when
  1185.      * checkboxToggle = true).  This method should never be called externally, but can be
  1186.      * overridden to provide custom behavior when the checkbox is toggled if needed.
  1187.      */
  1188.     onCheckClick : function(){
  1189.         this[this.checkbox.dom.checked ? 'expand' : 'collapse']();
  1190.     }
  1191.     /**
  1192.      * @cfg {String/Number} activeItem
  1193.      * @hide
  1194.      */
  1195.     /**
  1196.      * @cfg {Mixed} applyTo
  1197.      * @hide
  1198.      */
  1199.     /**
  1200.      * @cfg {Boolean} bodyBorder
  1201.      * @hide
  1202.      */
  1203.     /**
  1204.      * @cfg {Boolean} border
  1205.      * @hide
  1206.      */
  1207.     /**
  1208.      * @cfg {Boolean/Number} bufferResize
  1209.      * @hide
  1210.      */
  1211.     /**
  1212.      * @cfg {Boolean} collapseFirst
  1213.      * @hide
  1214.      */
  1215.     /**
  1216.      * @cfg {String} defaultType
  1217.      * @hide
  1218.      */
  1219.     /**
  1220.      * @cfg {String} disabledClass
  1221.      * @hide
  1222.      */
  1223.     /**
  1224.      * @cfg {String} elements
  1225.      * @hide
  1226.      */
  1227.     /**
  1228.      * @cfg {Boolean} floating
  1229.      * @hide
  1230.      */
  1231.     /**
  1232.      * @cfg {Boolean} footer
  1233.      * @hide
  1234.      */
  1235.     /**
  1236.      * @cfg {Boolean} frame
  1237.      * @hide
  1238.      */
  1239.     /**
  1240.      * @cfg {Boolean} header
  1241.      * @hide
  1242.      */
  1243.     /**
  1244.      * @cfg {Boolean} headerAsText
  1245.      * @hide
  1246.      */
  1247.     /**
  1248.      * @cfg {Boolean} hideCollapseTool
  1249.      * @hide
  1250.      */
  1251.     /**
  1252.      * @cfg {String} iconCls
  1253.      * @hide
  1254.      */
  1255.     /**
  1256.      * @cfg {Boolean/String} shadow
  1257.      * @hide
  1258.      */
  1259.     /**
  1260.      * @cfg {Number} shadowOffset
  1261.      * @hide
  1262.      */
  1263.     /**
  1264.      * @cfg {Boolean} shim
  1265.      * @hide
  1266.      */
  1267.     /**
  1268.      * @cfg {Object/Array} tbar
  1269.      * @hide
  1270.      */
  1271.     /**
  1272.      * @cfg {String} tabTip
  1273.      * @hide
  1274.      */
  1275.     /**
  1276.      * @cfg {Boolean} titleCollapse
  1277.      * @hide
  1278.      */
  1279.     /**
  1280.      * @cfg {Array} tools
  1281.      * @hide
  1282.      */
  1283.     /**
  1284.      * @cfg {Ext.Template/Ext.XTemplate} toolTemplate
  1285.      * @hide
  1286.      */
  1287.     /**
  1288.      * @cfg {String} xtype
  1289.      * @hide
  1290.      */
  1291.     /**
  1292.      * @property header
  1293.      * @hide
  1294.      */
  1295.     /**
  1296.      * @property footer
  1297.      * @hide
  1298.      */
  1299.     /**
  1300.      * @method focus
  1301.      * @hide
  1302.      */
  1303.     /**
  1304.      * @method getBottomToolbar
  1305.      * @hide
  1306.      */
  1307.     /**
  1308.      * @method getTopToolbar
  1309.      * @hide
  1310.      */
  1311.     /**
  1312.      * @method setIconClass
  1313.      * @hide
  1314.      */
  1315.     /**
  1316.      * @event activate
  1317.      * @hide
  1318.      */
  1319.     /**
  1320.      * @event beforeclose
  1321.      * @hide
  1322.      */
  1323.     /**
  1324.      * @event bodyresize
  1325.      * @hide
  1326.      */
  1327.     /**
  1328.      * @event close
  1329.      * @hide
  1330.      */
  1331.     /**
  1332.      * @event deactivate
  1333.      * @hide
  1334.      */
  1335. });
  1336. Ext.reg('fieldset', Ext.form.FieldSet);
  1337. /**
  1338.  * @class Ext.form.HtmlEditor
  1339.  * @extends Ext.form.Field
  1340.  * Provides a lightweight HTML Editor component. Some toolbar features are not supported by Safari and will be 
  1341.  * automatically hidden when needed.  These are noted in the config options where appropriate.
  1342.  * <br><br>The editor's toolbar buttons have tooltips defined in the {@link #buttonTips} property, but they are not 
  1343.  * enabled by default unless the global {@link Ext.QuickTips} singleton is {@link Ext.QuickTips#init initialized}.
  1344.  * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
  1345.  * supported by this editor.</b>
  1346.  * <br><br>An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
  1347.  * any element that has display set to 'none' can cause problems in Safari and Firefox due to their default iframe reloading bugs.
  1348.  * <br><br>Example usage:
  1349.  * <pre><code>
  1350. // Simple example rendered with default options:
  1351. Ext.QuickTips.init();  // enable tooltips
  1352. new Ext.form.HtmlEditor({
  1353.     renderTo: Ext.getBody(),
  1354.     width: 800,
  1355.     height: 300
  1356. });
  1357. // Passed via xtype into a container and with custom options:
  1358. Ext.QuickTips.init();  // enable tooltips
  1359. new Ext.Panel({
  1360.     title: 'HTML Editor',
  1361.     renderTo: Ext.getBody(),
  1362.     width: 600,
  1363.     height: 300,
  1364.     frame: true,
  1365.     layout: 'fit',
  1366.     items: {
  1367.         xtype: 'htmleditor',
  1368.         enableColors: false,
  1369.         enableAlignments: false
  1370.     }
  1371. });
  1372. </code></pre>
  1373.  * @constructor
  1374.  * Create a new HtmlEditor
  1375.  * @param {Object} config
  1376.  * @xtype htmleditor
  1377.  */
  1378. Ext.form.HtmlEditor = Ext.extend(Ext.form.Field, {
  1379.     /**
  1380.      * @cfg {Boolean} enableFormat Enable the bold, italic and underline buttons (defaults to true)
  1381.      */
  1382.     enableFormat : true,
  1383.     /**
  1384.      * @cfg {Boolean} enableFontSize Enable the increase/decrease font size buttons (defaults to true)
  1385.      */
  1386.     enableFontSize : true,
  1387.     /**
  1388.      * @cfg {Boolean} enableColors Enable the fore/highlight color buttons (defaults to true)
  1389.      */
  1390.     enableColors : true,
  1391.     /**
  1392.      * @cfg {Boolean} enableAlignments Enable the left, center, right alignment buttons (defaults to true)
  1393.      */
  1394.     enableAlignments : true,
  1395.     /**
  1396.      * @cfg {Boolean} enableLists Enable the bullet and numbered list buttons. Not available in Safari. (defaults to true)
  1397.      */
  1398.     enableLists : true,
  1399.     /**
  1400.      * @cfg {Boolean} enableSourceEdit Enable the switch to source edit button. Not available in Safari. (defaults to true)
  1401.      */
  1402.     enableSourceEdit : true,
  1403.     /**
  1404.      * @cfg {Boolean} enableLinks Enable the create link button. Not available in Safari. (defaults to true)
  1405.      */
  1406.     enableLinks : true,
  1407.     /**
  1408.      * @cfg {Boolean} enableFont Enable font selection. Not available in Safari. (defaults to true)
  1409.      */
  1410.     enableFont : true,
  1411.     /**
  1412.      * @cfg {String} createLinkText The default text for the create link prompt
  1413.      */
  1414.     createLinkText : 'Please enter the URL for the link:',
  1415.     /**
  1416.      * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
  1417.      */
  1418.     defaultLinkValue : 'http:/'+'/',
  1419.     /**
  1420.      * @cfg {Array} fontFamilies An array of available font families
  1421.      */
  1422.     fontFamilies : [
  1423.         'Arial',
  1424.         'Courier New',
  1425.         'Tahoma',
  1426.         'Times New Roman',
  1427.         'Verdana'
  1428.     ],
  1429.     defaultFont: 'tahoma',
  1430.     /**
  1431.      * @cfg {String} defaultValue A default value to be put into the editor to resolve focus issues (defaults to &#8203; (Zero-width space), &nbsp; (Non-breaking space) in Opera and IE6).
  1432.      */
  1433.     defaultValue: (Ext.isOpera || Ext.isIE6) ? '&nbsp;' : '&#8203;',
  1434.     // private properties
  1435.     actionMode: 'wrap',
  1436.     validationEvent : false,
  1437.     deferHeight: true,
  1438.     initialized : false,
  1439.     activated : false,
  1440.     sourceEditMode : false,
  1441.     onFocus : Ext.emptyFn,
  1442.     iframePad:3,
  1443.     hideMode:'offsets',
  1444.     defaultAutoCreate : {
  1445.         tag: "textarea",
  1446.         style:"width:500px;height:300px;",
  1447.         autocomplete: "off"
  1448.     },
  1449.     // private
  1450.     initComponent : function(){
  1451.         this.addEvents(
  1452.             /**
  1453.              * @event initialize
  1454.              * Fires when the editor is fully initialized (including the iframe)
  1455.              * @param {HtmlEditor} this
  1456.              */
  1457.             'initialize',
  1458.             /**
  1459.              * @event activate
  1460.              * Fires when the editor is first receives the focus. Any insertion must wait
  1461.              * until after this event.
  1462.              * @param {HtmlEditor} this
  1463.              */
  1464.             'activate',
  1465.              /**
  1466.              * @event beforesync
  1467.              * Fires before the textarea is updated with content from the editor iframe. Return false
  1468.              * to cancel the sync.
  1469.              * @param {HtmlEditor} this
  1470.              * @param {String} html
  1471.              */
  1472.             'beforesync',
  1473.              /**
  1474.              * @event beforepush
  1475.              * Fires before the iframe editor is updated with content from the textarea. Return false
  1476.              * to cancel the push.
  1477.              * @param {HtmlEditor} this
  1478.              * @param {String} html
  1479.              */
  1480.             'beforepush',
  1481.              /**
  1482.              * @event sync
  1483.              * Fires when the textarea is updated with content from the editor iframe.
  1484.              * @param {HtmlEditor} this
  1485.              * @param {String} html
  1486.              */
  1487.             'sync',
  1488.              /**
  1489.              * @event push
  1490.              * Fires when the iframe editor is updated with content from the textarea.
  1491.              * @param {HtmlEditor} this
  1492.              * @param {String} html
  1493.              */
  1494.             'push',
  1495.              /**
  1496.              * @event editmodechange
  1497.              * Fires when the editor switches edit modes
  1498.              * @param {HtmlEditor} this
  1499.              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
  1500.              */
  1501.             'editmodechange'
  1502.         )
  1503.     },
  1504.     // private
  1505.     createFontOptions : function(){
  1506.         var buf = [], fs = this.fontFamilies, ff, lc;
  1507.         for(var i = 0, len = fs.length; i< len; i++){
  1508.             ff = fs[i];
  1509.             lc = ff.toLowerCase();
  1510.             buf.push(
  1511.                 '<option value="',lc,'" style="font-family:',ff,';"',
  1512.                     (this.defaultFont == lc ? ' selected="true">' : '>'),
  1513.                     ff,
  1514.                 '</option>'
  1515.             );
  1516.         }
  1517.         return buf.join('');
  1518.     },
  1519.     
  1520.     /*
  1521.      * Protected method that will not generally be called directly. It
  1522.      * is called when the editor creates its toolbar. Override this method if you need to
  1523.      * add custom toolbar buttons.
  1524.      * @param {HtmlEditor} editor
  1525.      */
  1526.     createToolbar : function(editor){
  1527.         
  1528.         var tipsEnabled = Ext.QuickTips && Ext.QuickTips.isEnabled();
  1529.         
  1530.         function btn(id, toggle, handler){
  1531.             return {
  1532.                 itemId : id,
  1533.                 cls : 'x-btn-icon',
  1534.                 iconCls: 'x-edit-'+id,
  1535.                 enableToggle:toggle !== false,
  1536.                 scope: editor,
  1537.                 handler:handler||editor.relayBtnCmd,
  1538.                 clickEvent:'mousedown',
  1539.                 tooltip: tipsEnabled ? editor.buttonTips[id] || undefined : undefined,
  1540.                 overflowText: editor.buttonTips[id].title || undefined,
  1541.                 tabIndex:-1
  1542.             };
  1543.         }
  1544.         // build the toolbar
  1545.         var tb = new Ext.Toolbar({
  1546.             renderTo:this.wrap.dom.firstChild
  1547.         });
  1548.         // stop form submits
  1549.         this.mon(tb.el, 'click', function(e){
  1550.             e.preventDefault();
  1551.         });