commit extjs-2.2.1
[extjs.git] / source / widgets / form / Field.js
1 /*\r
2  * Ext JS Library 2.2.1\r
3  * Copyright(c) 2006-2009, Ext JS, LLC.\r
4  * licensing@extjs.com\r
5  * \r
6  * http://extjs.com/license\r
7  */\r
8 \r
9 /**\r
10  * @class Ext.form.Field\r
11  * @extends Ext.BoxComponent\r
12  * Base class for form fields that provides default event handling, sizing, value handling and other functionality.\r
13  * @constructor\r
14  * Creates a new Field\r
15  * @param {Object} config Configuration options\r
16  */\r
17 Ext.form.Field = Ext.extend(Ext.BoxComponent,  {\r
18     /**\r
19      * @cfg {String} fieldLabel The label text to display next to this field (defaults to '')\r
20      * <p><b>A Field's label is not by default rendered as part of the Field's structure.\r
21      * The label is rendered by the {@link Ext.layout.FormLayout form layout} layout manager\r
22      * of the {@link Ext.form.Container Container} to which the Field is added.</b></p>\r
23      */\r
24     /**\r
25      * @cfg {String} labelStyle A CSS style specification to apply directly to this field's label (defaults to the\r
26      * container's labelStyle value if set, or ''). For example, <code>labelStyle: 'font-weight:bold;'</code>.\r
27      */\r
28     /**\r
29      * @cfg {String} labelSeparator The standard separator to display after the text of each form label (defaults\r
30      * to the value of {@link Ext.layout.FormLayout#labelSeparator}, which is a colon ':' by default).  To display\r
31      * no separator for this field's label specify empty string ''.\r
32      */\r
33     /**\r
34      * @cfg {Boolean} hideLabel True to completely hide the label element (defaults to false)\r
35      */\r
36     /**\r
37      * @cfg {String} clearCls The CSS class used to provide field clearing (defaults to 'x-form-clear-left')\r
38      */\r
39     /**\r
40      * @cfg {String} itemCls An additional CSS class to apply to the wrapper's form item element of this field (defaults\r
41      * to the container's itemCls value if set, or '').  Since it is applied to the item wrapper, it allows you to write\r
42      * standard CSS rules that can apply to the field, the label (if specified) or any other element within the markup for\r
43      * the field. NOTE: this will not have any effect on fields that are not part of a form. Example use:\r
44      * <pre><code>\r
45 // Apply a style to the field's label:\r
46 &lt;style>\r
47     .required .x-form-item-label {font-weight:bold;color:red;}\r
48 &lt;/style>\r
49 \r
50 new Ext.FormPanel({\r
51         height: 100,\r
52         renderTo: document.body,\r
53         items: [{\r
54                 xtype: 'textfield',\r
55                 fieldLabel: 'Name',\r
56                 itemCls: 'required' //this label will be styled\r
57         },{\r
58                 xtype: 'textfield',\r
59                 fieldLabel: 'Favorite Color'\r
60         }]\r
61 });\r
62 </code></pre>\r
63      */\r
64     /**\r
65      * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password, file (defaults\r
66      * to "text"). The types "file" and "password" must be used to render those field types currently -- there are\r
67      * no separate Ext components for those. Note that if you use <tt>inputType:'file'</tt>, {@link #emptyText}\r
68      * is not supported and should be avoided.\r
69      */\r
70     /**\r
71      * @cfg {Number} tabIndex The tabIndex for this field. Note this only applies to fields that are rendered,\r
72      * not those which are built via applyTo (defaults to undefined).\r
73      */\r
74     /**\r
75      * @cfg {Mixed} value A value to initialize this field with (defaults to undefined).\r
76      */\r
77     /**\r
78      * @cfg {String} name The field's HTML name attribute (defaults to "").\r
79      */\r
80     /**\r
81      * @cfg {String} cls A custom CSS class to apply to the field's underlying element (defaults to "").\r
82      */\r
83 \r
84     /**\r
85      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")\r
86      */\r
87     invalidClass : "x-form-invalid",\r
88     /**\r
89      * @cfg {String} invalidText The error text to use when marking a field invalid and no message is provided\r
90      * (defaults to "The value in this field is invalid")\r
91      */\r
92     invalidText : "The value in this field is invalid",\r
93     /**\r
94      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")\r
95      */\r
96     focusClass : "x-form-focus",\r
97     /**\r
98      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable\r
99       automatic validation (defaults to "keyup").\r
100      */\r
101     validationEvent : "keyup",\r
102     /**\r
103      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).\r
104      */\r
105     validateOnBlur : true,\r
106     /**\r
107      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation\r
108      * is initiated (defaults to 250)\r
109      */\r
110     validationDelay : 250,\r
111     /**\r
112      * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to\r
113      * {tag: "input", type: "text", size: "20", autocomplete: "off"})\r
114      */\r
115     defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},\r
116     /**\r
117      * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")\r
118      */\r
119     fieldClass : "x-form-field",\r
120     /**\r
121      * @cfg {String} msgTarget The location where error text should display.  Should be one of the following values\r
122      * (defaults to 'qtip'):\r
123      *<pre>\r
124 Value         Description\r
125 -----------   ----------------------------------------------------------------------\r
126 qtip          Display a quick tip when the user hovers over the field\r
127 title         Display a default browser title attribute popup\r
128 under         Add a block div beneath the field containing the error text\r
129 side          Add an error icon to the right of the field with a popup on hover\r
130 [element id]  Add the error text directly to the innerHTML of the specified element\r
131 </pre>\r
132      */\r
133     msgTarget : 'qtip',\r
134     /**\r
135      * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field\r
136      * (defaults to 'normal').\r
137      */\r
138     msgFx : 'normal',\r
139     /**\r
140      * @cfg {Boolean} readOnly True to mark the field as readOnly in HTML (defaults to false) -- Note: this only\r
141      * sets the element's readOnly DOM attribute.\r
142      */\r
143     readOnly : false,\r
144     /**\r
145      * @cfg {Boolean} disabled True to disable the field (defaults to false).\r
146      * <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>,\r
147      * disabled Fields will not be {@link Ext.form.BasicForm#submit submitted}.</p>\r
148      */\r
149     disabled : false,\r
150 \r
151     // private\r
152     isFormField : true,\r
153 \r
154     // private\r
155     hasFocus : false,\r
156 \r
157         // private\r
158         initComponent : function(){\r
159         Ext.form.Field.superclass.initComponent.call(this);\r
160         this.addEvents(\r
161             /**\r
162              * @event focus\r
163              * Fires when this field receives input focus.\r
164              * @param {Ext.form.Field} this\r
165              */\r
166             'focus',\r
167             /**\r
168              * @event blur\r
169              * Fires when this field loses input focus.\r
170              * @param {Ext.form.Field} this\r
171              */\r
172             'blur',\r
173             /**\r
174              * @event specialkey\r
175              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check\r
176              * {@link Ext.EventObject#getKey} to determine which key was pressed.\r
177              * @param {Ext.form.Field} this\r
178              * @param {Ext.EventObject} e The event object\r
179              */\r
180             'specialkey',\r
181             /**\r
182              * @event change\r
183              * Fires just before the field blurs if the field value has changed.\r
184              * @param {Ext.form.Field} this\r
185              * @param {Mixed} newValue The new value\r
186              * @param {Mixed} oldValue The original value\r
187              */\r
188             'change',\r
189             /**\r
190              * @event invalid\r
191              * Fires after the field has been marked as invalid.\r
192              * @param {Ext.form.Field} this\r
193              * @param {String} msg The validation message\r
194              */\r
195             'invalid',\r
196             /**\r
197              * @event valid\r
198              * Fires after the field has been validated with no errors.\r
199              * @param {Ext.form.Field} this\r
200              */\r
201             'valid'\r
202         );\r
203     },\r
204 \r
205     /**\r
206      * Returns the name attribute of the field if available\r
207      * @return {String} name The field name\r
208      */\r
209     getName: function(){\r
210          return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');\r
211     },\r
212 \r
213     // private\r
214     onRender : function(ct, position){\r
215         Ext.form.Field.superclass.onRender.call(this, ct, position);\r
216         if(!this.el){\r
217             var cfg = this.getAutoCreate();\r
218             if(!cfg.name){\r
219                 cfg.name = this.name || this.id;\r
220             }\r
221             if(this.inputType){\r
222                 cfg.type = this.inputType;\r
223             }\r
224             this.el = ct.createChild(cfg, position);\r
225         }\r
226         var type = this.el.dom.type;\r
227         if(type){\r
228             if(type == 'password'){\r
229                 type = 'text';\r
230             }\r
231             this.el.addClass('x-form-'+type);\r
232         }\r
233         if(this.readOnly){\r
234             this.el.dom.readOnly = true;\r
235         }\r
236         if(this.tabIndex !== undefined){\r
237             this.el.dom.setAttribute('tabIndex', this.tabIndex);\r
238         }\r
239 \r
240         this.el.addClass([this.fieldClass, this.cls]);\r
241     },\r
242 \r
243     // private\r
244     initValue : function(){\r
245         if(this.value !== undefined){\r
246             this.setValue(this.value);\r
247         }else if(this.el.dom.value.length > 0 && this.el.dom.value != this.emptyText){\r
248             this.setValue(this.el.dom.value);\r
249         }\r
250         // reference to original value for reset\r
251         this.originalValue = this.getValue();\r
252     },\r
253 \r
254     /**\r
255      * Returns true if this field has been changed since it was originally loaded and is not disabled.\r
256      */\r
257     isDirty : function() {\r
258         if(this.disabled) {\r
259             return false;\r
260         }\r
261         return String(this.getValue()) !== String(this.originalValue);\r
262     },\r
263 \r
264     // private\r
265     afterRender : function(){\r
266         Ext.form.Field.superclass.afterRender.call(this);\r
267         this.initEvents();\r
268         this.initValue();\r
269     },\r
270 \r
271     // private\r
272     fireKey : function(e){\r
273         if(e.isSpecialKey()){\r
274             this.fireEvent("specialkey", this, e);\r
275         }\r
276     },\r
277 \r
278     /**\r
279      * Resets the current field value to the originally loaded value and clears any validation messages\r
280      */\r
281     reset : function(){\r
282         this.setValue(this.originalValue);\r
283         this.clearInvalid();\r
284     },\r
285 \r
286     // private\r
287     initEvents : function(){\r
288         this.el.on(Ext.isIE || Ext.isSafari3 ? "keydown" : "keypress", this.fireKey,  this);\r
289         this.el.on("focus", this.onFocus,  this);\r
290 \r
291         // fix weird FF/Win editor issue when changing OS window focus\r
292         var o = this.inEditor && Ext.isWindows && Ext.isGecko ? {buffer:10} : null;\r
293         this.el.on("blur", this.onBlur,  this, o);\r
294     },\r
295 \r
296     // private\r
297     onFocus : function(){\r
298         if(this.focusClass){\r
299             this.el.addClass(this.focusClass);\r
300         }\r
301         if(!this.hasFocus){\r
302             this.hasFocus = true;\r
303             this.startValue = this.getValue();\r
304             this.fireEvent("focus", this);\r
305         }\r
306     },\r
307 \r
308     // private\r
309     beforeBlur : Ext.emptyFn,\r
310 \r
311     // private\r
312     onBlur : function(){\r
313         this.beforeBlur();\r
314         if(this.focusClass){\r
315             this.el.removeClass(this.focusClass);\r
316         }\r
317         this.hasFocus = false;\r
318         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){\r
319             this.validate();\r
320         }\r
321         var v = this.getValue();\r
322         if(String(v) !== String(this.startValue)){\r
323             this.fireEvent('change', this, v, this.startValue);\r
324         }\r
325         this.fireEvent("blur", this);\r
326     },\r
327 \r
328     /**\r
329      * Returns whether or not the field value is currently valid\r
330      * @param {Boolean} preventMark True to disable marking the field invalid\r
331      * @return {Boolean} True if the value is valid, else false\r
332      */\r
333     isValid : function(preventMark){\r
334         if(this.disabled){\r
335             return true;\r
336         }\r
337         var restore = this.preventMark;\r
338         this.preventMark = preventMark === true;\r
339         var v = this.validateValue(this.processValue(this.getRawValue()));\r
340         this.preventMark = restore;\r
341         return v;\r
342     },\r
343 \r
344     /**\r
345      * Validates the field value\r
346      * @return {Boolean} True if the value is valid, else false\r
347      */\r
348     validate : function(){\r
349         if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){\r
350             this.clearInvalid();\r
351             return true;\r
352         }\r
353         return false;\r
354     },\r
355 \r
356     // protected - should be overridden by subclasses if necessary to prepare raw values for validation\r
357     processValue : function(value){\r
358         return value;\r
359     },\r
360 \r
361     // private\r
362     // Subclasses should provide the validation implementation by overriding this\r
363     validateValue : function(value){\r
364         return true;\r
365     },\r
366 \r
367     /**\r
368      * Mark this field as invalid, using {@link #msgTarget} to determine how to display the error and\r
369      * applying {@link #invalidClass} to the field's element.\r
370      * @param {String} msg (optional) The validation message (defaults to {@link #invalidText})\r
371      */\r
372     markInvalid : function(msg){\r
373         if(!this.rendered || this.preventMark){ // not rendered\r
374             return;\r
375         }\r
376         this.el.addClass(this.invalidClass);\r
377         msg = msg || this.invalidText;\r
378 \r
379         switch(this.msgTarget){\r
380             case 'qtip':\r
381                 this.el.dom.qtip = msg;\r
382                 this.el.dom.qclass = 'x-form-invalid-tip';\r
383                 if(Ext.QuickTips){ // fix for floating editors interacting with DND\r
384                     Ext.QuickTips.enable();\r
385                 }\r
386                 break;\r
387             case 'title':\r
388                 this.el.dom.title = msg;\r
389                 break;\r
390             case 'under':\r
391                 if(!this.errorEl){\r
392                     var elp = this.getErrorCt();\r
393                     if(!elp){ // field has no container el\r
394                         this.el.dom.title = msg;\r
395                         break;\r
396                     }\r
397                     this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});\r
398                     this.errorEl.setWidth(elp.getWidth(true)-20);\r
399                 }\r
400                 this.errorEl.update(msg);\r
401                 Ext.form.Field.msgFx[this.msgFx].show(this.errorEl, this);\r
402                 break;\r
403             case 'side':\r
404                 if(!this.errorIcon){\r
405                     var elp = this.getErrorCt();\r
406                     if(!elp){ // field has no container el\r
407                         this.el.dom.title = msg;\r
408                         break;\r
409                     }\r
410                     this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});\r
411                 }\r
412                 this.alignErrorIcon();\r
413                 this.errorIcon.dom.qtip = msg;\r
414                 this.errorIcon.dom.qclass = 'x-form-invalid-tip';\r
415                 this.errorIcon.show();\r
416                 this.on('resize', this.alignErrorIcon, this);\r
417                 break;\r
418             default:\r
419                 var t = Ext.getDom(this.msgTarget);\r
420                 t.innerHTML = msg;\r
421                 t.style.display = this.msgDisplay;\r
422                 break;\r
423         }\r
424         this.fireEvent('invalid', this, msg);\r
425     },\r
426 \r
427     // private\r
428     getErrorCt : function(){\r
429         return this.el.findParent('.x-form-element', 5, true) || // use form element wrap if available\r
430             this.el.findParent('.x-form-field-wrap', 5, true);   // else direct field wrap\r
431     },\r
432 \r
433     // private\r
434     alignErrorIcon : function(){\r
435         this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);\r
436     },\r
437 \r
438     /**\r
439      * Clear any invalid styles/messages for this field\r
440      */\r
441     clearInvalid : function(){\r
442         if(!this.rendered || this.preventMark){ // not rendered\r
443             return;\r
444         }\r
445         this.el.removeClass(this.invalidClass);\r
446         switch(this.msgTarget){\r
447             case 'qtip':\r
448                 this.el.dom.qtip = '';\r
449                 break;\r
450             case 'title':\r
451                 this.el.dom.title = '';\r
452                 break;\r
453             case 'under':\r
454                 if(this.errorEl){\r
455                     Ext.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);\r
456                 }\r
457                 break;\r
458             case 'side':\r
459                 if(this.errorIcon){\r
460                     this.errorIcon.dom.qtip = '';\r
461                     this.errorIcon.hide();\r
462                     this.un('resize', this.alignErrorIcon, this);\r
463                 }\r
464                 break;\r
465             default:\r
466                 var t = Ext.getDom(this.msgTarget);\r
467                 t.innerHTML = '';\r
468                 t.style.display = 'none';\r
469                 break;\r
470         }\r
471         this.fireEvent('valid', this);\r
472     },\r
473 \r
474     /**\r
475      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.\r
476      * @return {Mixed} value The field value\r
477      */\r
478     getRawValue : function(){\r
479         var v = this.rendered ? this.el.getValue() : Ext.value(this.value, '');\r
480         if(v === this.emptyText){\r
481             v = '';\r
482         }\r
483         return v;\r
484     },\r
485 \r
486     /**\r
487      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.\r
488      * @return {Mixed} value The field value\r
489      */\r
490     getValue : function(){\r
491         if(!this.rendered) {\r
492             return this.value;\r
493         }\r
494         var v = this.el.getValue();\r
495         if(v === this.emptyText || v === undefined){\r
496             v = '';\r
497         }\r
498         return v;\r
499     },\r
500 \r
501     /**\r
502      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.\r
503      * @param {Mixed} value The value to set\r
504      * @return {Mixed} value The field value that is set\r
505      */\r
506     setRawValue : function(v){\r
507         return this.el.dom.value = (v === null || v === undefined ? '' : v);\r
508     },\r
509 \r
510     /**\r
511      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.\r
512      * @param {Mixed} value The value to set\r
513      */\r
514     setValue : function(v){\r
515         this.value = v;\r
516         if(this.rendered){\r
517             this.el.dom.value = (v === null || v === undefined ? '' : v);\r
518             this.validate();\r
519         }\r
520     },\r
521 \r
522     // private\r
523     adjustSize : function(w, h){\r
524         var s = Ext.form.Field.superclass.adjustSize.call(this, w, h);\r
525         s.width = this.adjustWidth(this.el.dom.tagName, s.width);\r
526         return s;\r
527     },\r
528 \r
529     // private\r
530     adjustWidth : function(tag, w){\r
531         tag = tag.toLowerCase();\r
532         if(typeof w == 'number' && !Ext.isSafari){\r
533             if(Ext.isIE && (tag == 'input' || tag == 'textarea')){\r
534                 if(tag == 'input' && !Ext.isStrict){\r
535                     return this.inEditor ? w : w - 3;\r
536                 }\r
537                 if(tag == 'input' && Ext.isStrict){\r
538                     return w - (Ext.isIE6 ? 4 : 1);\r
539                 }\r
540                 if(tag == 'textarea' && Ext.isStrict){\r
541                     return w-2;\r
542                 }\r
543             }else if(Ext.isOpera && Ext.isStrict){\r
544                 if(tag == 'input'){\r
545                     return w + 2;\r
546                 }\r
547                 if(tag == 'textarea'){\r
548                     return w-2;\r
549                 }\r
550             }\r
551         }\r
552         return w;\r
553     }\r
554 \r
555     /**\r
556      * @cfg {Boolean} autoWidth @hide\r
557      */\r
558     /**\r
559      * @cfg {Boolean} autoHeight @hide\r
560      */\r
561 \r
562     /**\r
563      * @cfg {String} autoEl @hide\r
564      */\r
565 });\r
566 \r
567 Ext.form.MessageTargets = {\r
568     'qtip' : {\r
569         mark: function(f){\r
570             this.el.dom.qtip = msg;\r
571             this.el.dom.qclass = 'x-form-invalid-tip';\r
572             if(Ext.QuickTips){ // fix for floating editors interacting with DND\r
573                 Ext.QuickTips.enable();\r
574             }\r
575         },\r
576         clear: function(f){\r
577             this.el.dom.qtip = '';\r
578         }\r
579     },\r
580     'title' : {\r
581         mark: function(f){\r
582             this.el.dom.title = msg;\r
583         },\r
584         clear: function(f){\r
585             this.el.dom.title = '';\r
586         }\r
587     },\r
588     'under' : {\r
589         mark: function(f){\r
590             if(!this.errorEl){\r
591                 var elp = this.getErrorCt();\r
592                 if(!elp){ // field has no container el\r
593                     this.el.dom.title = msg;\r
594                     return;\r
595                 }\r
596                 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});\r
597                 this.errorEl.setWidth(elp.getWidth(true)-20);\r
598             }\r
599             this.errorEl.update(msg);\r
600             Ext.form.Field.msgFx[this.msgFx].show(this.errorEl, this);\r
601         },\r
602         clear: function(f){\r
603             if(this.errorEl){\r
604                 Ext.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);\r
605             }else{\r
606                 this.el.dom.title = '';\r
607             }\r
608         }\r
609     },\r
610     'side' : {\r
611         mark: function(f){\r
612             if(!this.errorIcon){\r
613                 var elp = this.getErrorCt();\r
614                 if(!elp){ // field has no container el\r
615                     this.el.dom.title = msg;\r
616                     return;\r
617                 }\r
618                 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});\r
619             }\r
620             this.alignErrorIcon();\r
621             this.errorIcon.dom.qtip = msg;\r
622             this.errorIcon.dom.qclass = 'x-form-invalid-tip';\r
623             this.errorIcon.show();\r
624             this.on('resize', this.alignErrorIcon, this);\r
625         },\r
626         clear: function(f){\r
627             if(this.errorIcon){\r
628                 this.errorIcon.dom.qtip = '';\r
629                 this.errorIcon.hide();\r
630                 this.un('resize', this.alignErrorIcon, this);\r
631             }else{\r
632                 this.el.dom.title = '';\r
633             }\r
634         }\r
635     },\r
636     'around' : {\r
637         mark: function(f){\r
638 \r
639         },\r
640         clear: function(f){\r
641 \r
642         }\r
643     }\r
644 };\r
645 \r
646 \r
647 // anything other than normal should be considered experimental\r
648 Ext.form.Field.msgFx = {\r
649     normal : {\r
650         show: function(msgEl, f){\r
651             msgEl.setDisplayed('block');\r
652         },\r
653 \r
654         hide : function(msgEl, f){\r
655             msgEl.setDisplayed(false).update('');\r
656         }\r
657     },\r
658 \r
659     slide : {\r
660         show: function(msgEl, f){\r
661             msgEl.slideIn('t', {stopFx:true});\r
662         },\r
663 \r
664         hide : function(msgEl, f){\r
665             msgEl.slideOut('t', {stopFx:true,useDisplay:true});\r
666         }\r
667     },\r
668 \r
669     slideRight : {\r
670         show: function(msgEl, f){\r
671             msgEl.fixDisplay();\r
672             msgEl.alignTo(f.el, 'tl-tr');\r
673             msgEl.slideIn('l', {stopFx:true});\r
674         },\r
675 \r
676         hide : function(msgEl, f){\r
677             msgEl.slideOut('l', {stopFx:true,useDisplay:true});\r
678         }\r
679     }\r
680 };\r
681 Ext.reg('field', Ext.form.Field);\r