3 * Copyright(c) 2006-2009 Ext JS, LLC
5 * http://www.extjs.com/license
8 * @class Ext.form.Field
9 * @extends Ext.BoxComponent
10 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
13 * @param {Object} config Configuration options
16 Ext.form.Field = Ext.extend(Ext.BoxComponent, {
18 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password, file (defaults
19 * to "text"). The types "file" and "password" must be used to render those field types currently -- there are
20 * no separate Ext components for those. Note that if you use <tt>inputType:'file'</tt>, {@link #emptyText}
21 * is not supported and should be avoided.
24 * @cfg {Number} tabIndex The tabIndex for this field. Note this only applies to fields that are rendered,
25 * not those which are built via applyTo (defaults to undefined).
28 * @cfg {Mixed} value A value to initialize this field with (defaults to undefined).
31 * @cfg {String} name The field's HTML name attribute (defaults to "").
32 * <b>Note</b>: this property must be set if this field is to be automatically included with
33 * {@link Ext.form.BasicForm#submit form submit()}.
36 * @cfg {String} cls A custom CSS class to apply to the field's underlying element (defaults to "").
40 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
42 invalidClass : "x-form-invalid",
44 * @cfg {String} invalidText The error text to use when marking a field invalid and no message is provided
45 * (defaults to "The value in this field is invalid")
47 invalidText : "The value in this field is invalid",
49 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
51 focusClass : "x-form-focus",
53 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
54 automatic validation (defaults to "keyup").
56 validationEvent : "keyup",
58 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
60 validateOnBlur : true,
62 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation
63 * is initiated (defaults to 250)
65 validationDelay : 250,
67 * @cfg {String/Object} autoCreate <p>A {@link Ext.DomHelper DomHelper} element spec, or true for a default
68 * element spec. Used to create the {@link Ext.Component#getEl Element} which will encapsulate this Component.
69 * See <tt>{@link Ext.Component#autoEl autoEl}</tt> for details. Defaults to:</p>
70 * <pre><code>{tag: "input", type: "text", size: "20", autocomplete: "off"}</code></pre>
72 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
74 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
76 fieldClass : "x-form-field",
78 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values
79 * (defaults to 'qtip'):
82 ----------- ----------------------------------------------------------------------
83 qtip Display a quick tip when the user hovers over the field
84 title Display a default browser title attribute popup
85 under Add a block div beneath the field containing the error text
86 side Add an error icon to the right of the field with a popup on hover
87 [element id] Add the error text directly to the innerHTML of the specified element
92 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field
93 * (defaults to 'normal').
97 * @cfg {Boolean} readOnly <tt>true</tt> to mark the field as readOnly in HTML
98 * (defaults to <tt>false</tt>).
99 * <br><p><b>Note</b>: this only sets the element's readOnly DOM attribute.
100 * Setting <code>readOnly=true</code>, for example, will not disable triggering a
101 * ComboBox or DateField; it gives you the option of forcing the user to choose
102 * via the trigger without typing in the text box. To hide the trigger use
103 * <code>{@link Ext.form.TriggerField#hideTrigger hideTrigger}</code>.</p>
107 * @cfg {Boolean} disabled True to disable the field (defaults to false).
108 * <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>,
109 * disabled Fields will not be {@link Ext.form.BasicForm#submit submitted}.</p>
120 initComponent : function(){
121 Ext.form.Field.superclass.initComponent.call(this);
125 * Fires when this field receives input focus.
126 * @param {Ext.form.Field} this
131 * Fires when this field loses input focus.
132 * @param {Ext.form.Field} this
137 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.
138 * To handle other keys see {@link Ext.Panel#keys} or {@link Ext.KeyMap}.
139 * You can check {@link Ext.EventObject#getKey} to determine which key was pressed.
140 * For example: <pre><code>
141 var form = new Ext.form.FormPanel({
144 fieldLabel: 'Field 1',
148 fieldLabel: 'Field 2',
151 specialkey: function(field, e){
152 // e.HOME, e.END, e.PAGE_UP, e.PAGE_DOWN,
153 // e.TAB, e.ESC, arrow keys: e.LEFT, e.RIGHT, e.UP, e.DOWN
154 if (e.{@link Ext.EventObject#getKey getKey()} == e.ENTER) {
155 var form = field.ownerCt.getForm();
165 * @param {Ext.form.Field} this
166 * @param {Ext.EventObject} e The event object
171 * Fires just before the field blurs if the field value has changed.
172 * @param {Ext.form.Field} this
173 * @param {Mixed} newValue The new value
174 * @param {Mixed} oldValue The original value
179 * Fires after the field has been marked as invalid.
180 * @param {Ext.form.Field} this
181 * @param {String} msg The validation message
186 * Fires after the field has been validated with no errors.
187 * @param {Ext.form.Field} this
194 * Returns the {@link Ext.form.Field#name name} or {@link Ext.form.ComboBox#hiddenName hiddenName}
195 * attribute of the field if available.
196 * @return {String} name The field {@link Ext.form.Field#name name} or {@link Ext.form.ComboBox#hiddenName hiddenName}
199 return this.rendered && this.el.dom.name ? this.el.dom.name : this.name || this.id || '';
203 onRender : function(ct, position){
205 var cfg = this.getAutoCreate();
208 cfg.name = this.name || this.id;
211 cfg.type = this.inputType;
215 Ext.form.Field.superclass.onRender.call(this, ct, position);
217 var type = this.el.dom.type;
219 if(type == 'password'){
222 this.el.addClass('x-form-'+type);
225 this.el.dom.readOnly = true;
227 if(this.tabIndex !== undefined){
228 this.el.dom.setAttribute('tabIndex', this.tabIndex);
231 this.el.addClass([this.fieldClass, this.cls]);
235 getItemCt : function(){
236 return this.el.up('.x-form-item', 4);
240 initValue : function(){
241 if(this.value !== undefined){
242 this.setValue(this.value);
243 }else if(!Ext.isEmpty(this.el.dom.value) && this.el.dom.value != this.emptyText){
244 this.setValue(this.el.dom.value);
247 * The original value of the field as configured in the {@link #value} configuration, or
248 * as loaded by the last form load operation if the form's {@link Ext.form.BasicForm#trackResetOnLoad trackResetOnLoad}
249 * setting is <code>true</code>.
251 * @property originalValue
253 this.originalValue = this.getValue();
257 * <p>Returns true if the value of this Field has been changed from its original value.
258 * Will return false if the field is disabled or has not been rendered yet.</p>
259 * <p>Note that if the owning {@link Ext.form.BasicForm form} was configured with
260 * {@link Ext.form.BasicForm}.{@link Ext.form.BasicForm#trackResetOnLoad trackResetOnLoad}
261 * then the <i>original value</i> is updated when the values are loaded by
262 * {@link Ext.form.BasicForm}.{@link Ext.form.BasicForm#setValues setValues}.</p>
263 * @return {Boolean} True if this field has been changed from its original value (and
264 * is not disabled), false otherwise.
266 isDirty : function() {
267 if(this.disabled || !this.rendered) {
270 return String(this.getValue()) !== String(this.originalValue);
274 afterRender : function(){
275 Ext.form.Field.superclass.afterRender.call(this);
281 fireKey : function(e){
282 if(e.isSpecialKey()){
283 this.fireEvent("specialkey", this, e);
288 * Resets the current field value to the originally loaded value and clears any validation messages.
289 * See {@link Ext.form.BasicForm}.{@link Ext.form.BasicForm#trackResetOnLoad trackResetOnLoad}
292 this.setValue(this.originalValue);
297 initEvents : function(){
298 this.mon(this.el, Ext.EventManager.useKeydown ? "keydown" : "keypress", this.fireKey, this);
299 this.mon(this.el, 'focus', this.onFocus, this);
301 // fix weird FF/Win editor issue when changing OS window focus
302 var o = this.inEditor && Ext.isWindows && Ext.isGecko ? {buffer:10} : null;
303 this.mon(this.el, 'blur', this.onBlur, this, o);
307 onFocus : function(){
309 this.el.addClass(this.focusClass);
312 this.hasFocus = true;
313 this.startValue = this.getValue();
314 this.fireEvent("focus", this);
319 beforeBlur : Ext.emptyFn,
325 this.el.removeClass(this.focusClass);
327 this.hasFocus = false;
328 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
331 var v = this.getValue();
332 if(String(v) !== String(this.startValue)){
333 this.fireEvent('change', this, v, this.startValue);
335 this.fireEvent("blur", this);
339 * Returns whether or not the field value is currently valid
340 * @param {Boolean} preventMark True to disable marking the field invalid
341 * @return {Boolean} True if the value is valid, else false
343 isValid : function(preventMark){
347 var restore = this.preventMark;
348 this.preventMark = preventMark === true;
349 var v = this.validateValue(this.processValue(this.getRawValue()));
350 this.preventMark = restore;
355 * Validates the field value
356 * @return {Boolean} True if the value is valid, else false
358 validate : function(){
359 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
366 // protected - should be overridden by subclasses if necessary to prepare raw values for validation
367 processValue : function(value){
372 // Subclasses should provide the validation implementation by overriding this
373 validateValue : function(value){
378 * Mark this field as invalid, using {@link #msgTarget} to determine how to display the error and
379 * applying {@link #invalidClass} to the field's element.
380 * @param {String} msg (optional) The validation message (defaults to {@link #invalidText})
382 markInvalid : function(msg){
383 if(!this.rendered || this.preventMark){ // not rendered
386 msg = msg || this.invalidText;
388 var mt = this.getMessageHandler();
391 }else if(this.msgTarget){
392 this.el.addClass(this.invalidClass);
393 var t = Ext.getDom(this.msgTarget);
396 t.style.display = this.msgDisplay;
399 this.fireEvent('invalid', this, msg);
403 * Clear any invalid styles/messages for this field
405 clearInvalid : function(){
406 if(!this.rendered || this.preventMark){ // not rendered
409 this.el.removeClass(this.invalidClass);
410 var mt = this.getMessageHandler();
413 }else if(this.msgTarget){
414 this.el.removeClass(this.invalidClass);
415 var t = Ext.getDom(this.msgTarget);
418 t.style.display = 'none';
421 this.fireEvent('valid', this);
425 getMessageHandler : function(){
426 return Ext.form.MessageTargets[this.msgTarget];
430 getErrorCt : function(){
431 return this.el.findParent('.x-form-element', 5, true) || // use form element wrap if available
432 this.el.findParent('.x-form-field-wrap', 5, true); // else direct field wrap
436 alignErrorIcon : function(){
437 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
441 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
442 * @return {Mixed} value The field value
444 getRawValue : function(){
445 var v = this.rendered ? this.el.getValue() : Ext.value(this.value, '');
446 if(v === this.emptyText){
453 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
454 * @return {Mixed} value The field value
456 getValue : function(){
460 var v = this.el.getValue();
461 if(v === this.emptyText || v === undefined){
468 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
469 * @param {Mixed} value The value to set
470 * @return {Mixed} value The field value that is set
472 setRawValue : function(v){
473 return (this.el.dom.value = (Ext.isEmpty(v) ? '' : v));
477 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
478 * @param {Mixed} value The value to set
479 * @return {Ext.form.Field} this
481 setValue : function(v){
484 this.el.dom.value = (Ext.isEmpty(v) ? '' : v);
490 // private, does not work for all fields
491 append : function(v){
492 this.setValue([this.getValue(), v].join(''));
496 adjustSize : function(w, h){
497 var s = Ext.form.Field.superclass.adjustSize.call(this, w, h);
498 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
500 var ct = this.getItemCt();
501 s.width -= ct.getFrameWidth('lr');
502 s.height -= ct.getFrameWidth('tb');
508 adjustWidth : function(tag, w){
509 if(typeof w == 'number' && (Ext.isIE && (Ext.isIE6 || !Ext.isStrict)) && /input|textarea/i.test(tag) && !this.inEditor){
516 * @cfg {Boolean} autoWidth @hide
519 * @cfg {Boolean} autoHeight @hide
523 * @cfg {String} autoEl @hide
528 Ext.form.MessageTargets = {
530 mark: function(field, msg){
531 field.el.addClass(field.invalidClass);
532 field.el.dom.qtip = msg;
533 field.el.dom.qclass = 'x-form-invalid-tip';
534 if(Ext.QuickTips){ // fix for floating editors interacting with DND
535 Ext.QuickTips.enable();
538 clear: function(field){
539 field.el.removeClass(field.invalidClass);
540 field.el.dom.qtip = '';
544 mark: function(field, msg){
545 field.el.addClass(field.invalidClass);
546 field.el.dom.title = msg;
548 clear: function(field){
549 field.el.dom.title = '';
553 mark: function(field, msg){
554 field.el.addClass(field.invalidClass);
556 var elp = field.getErrorCt();
557 if(!elp){ // field has no container el
558 field.el.dom.title = msg;
561 field.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
562 field.errorEl.setWidth(elp.getWidth(true)-20);
564 field.errorEl.update(msg);
565 Ext.form.Field.msgFx[field.msgFx].show(field.errorEl, field);
567 clear: function(field){
568 field.el.removeClass(field.invalidClass);
570 Ext.form.Field.msgFx[field.msgFx].hide(field.errorEl, field);
572 field.el.dom.title = '';
577 mark: function(field, msg){
578 field.el.addClass(field.invalidClass);
579 if(!field.errorIcon){
580 var elp = field.getErrorCt();
581 if(!elp){ // field has no container el
582 field.el.dom.title = msg;
585 field.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
587 field.alignErrorIcon();
588 field.errorIcon.dom.qtip = msg;
589 field.errorIcon.dom.qclass = 'x-form-invalid-tip';
590 field.errorIcon.show();
591 field.on('resize', field.alignErrorIcon, field);
593 clear: function(field){
594 field.el.removeClass(field.invalidClass);
596 field.errorIcon.dom.qtip = '';
597 field.errorIcon.hide();
598 field.un('resize', field.alignErrorIcon, field);
600 field.el.dom.title = '';
606 // anything other than normal should be considered experimental
607 Ext.form.Field.msgFx = {
609 show: function(msgEl, f){
610 msgEl.setDisplayed('block');
613 hide : function(msgEl, f){
614 msgEl.setDisplayed(false).update('');
619 show: function(msgEl, f){
620 msgEl.slideIn('t', {stopFx:true});
623 hide : function(msgEl, f){
624 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
629 show: function(msgEl, f){
631 msgEl.alignTo(f.el, 'tl-tr');
632 msgEl.slideIn('l', {stopFx:true});
635 hide : function(msgEl, f){
636 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
640 Ext.reg('field', Ext.form.Field);
642 * @class Ext.form.TextField
643 * @extends Ext.form.Field
644 * <p>Basic text field. Can be used as a direct replacement for traditional text inputs,
645 * or as the base class for more sophisticated input controls (like {@link Ext.form.TextArea}
646 * and {@link Ext.form.ComboBox}).</p>
647 * <p><b><u>Validation</u></b></p>
648 * <p>Field validation is processed in a particular order. If validation fails at any particular
649 * step the validation routine halts.</p>
650 * <div class="mdetail-params"><ul>
651 * <li><b>1. Field specific validator</b>
652 * <div class="sub-desc">
653 * <p>If a field is configured with a <code>{@link Ext.form.TextField#validator validator}</code> function,
654 * it will be passed the current field value. The <code>{@link Ext.form.TextField#validator validator}</code>
655 * function is expected to return boolean <tt>true</tt> if the value is valid or return a string to
656 * represent the invalid message if invalid.</p>
658 * <li><b>2. Built in Validation</b>
659 * <div class="sub-desc">
660 * <p>Basic validation is affected with the following configuration properties:</p>
662 * <u>Validation</u> <u>Invalid Message</u>
663 * <code>{@link Ext.form.TextField#allowBlank allowBlank} {@link Ext.form.TextField#emptyText emptyText}</code>
664 * <code>{@link Ext.form.TextField#minLength minLength} {@link Ext.form.TextField#minLengthText minLengthText}</code>
665 * <code>{@link Ext.form.TextField#maxLength maxLength} {@link Ext.form.TextField#maxLengthText maxLengthText}</code>
668 * <li><b>3. Preconfigured Validation Types (VTypes)</b>
669 * <div class="sub-desc">
670 * <p>Using VTypes offers a convenient way to reuse validation. If a field is configured with a
671 * <code>{@link Ext.form.TextField#vtype vtype}</code>, the corresponding {@link Ext.form.VTypes VTypes}
672 * validation function will be used for validation. If invalid, either the field's
673 * <code>{@link Ext.form.TextField#vtypeText vtypeText}</code> or the VTypes vtype Text property will be
674 * used for the invalid message. Keystrokes on the field will be filtered according to the VTypes
675 * vtype Mask property.</p>
677 * <li><b>4. Field specific regex test</b>
678 * <div class="sub-desc">
679 * <p>Each field may also specify a <code>{@link Ext.form.TextField#regex regex}</code> test.
680 * The invalid message for this test is configured with
681 * <code>{@link Ext.form.TextField#regexText regexText}</code>.</p>
683 * <li><b>Alter Validation Behavior</b>
684 * <div class="sub-desc">
685 * <p>Validation behavior for each field can be configured:</p><ul>
686 * <li><code>{@link Ext.form.TextField#invalidText invalidText}</code> : the default validation message to
687 * show if any validation step above does not provide a message when invalid</li>
688 * <li><code>{@link Ext.form.TextField#maskRe maskRe}</code> : filter out keystrokes before any validation occurs</li>
689 * <li><code>{@link Ext.form.TextField#stripCharsRe stripCharsRe}</code> : filter characters after being typed in,
690 * but before being validated</li>
691 * <li><code>{@link Ext.form.Field#invalidClass invalidClass}</code> : alternate style when invalid</li>
692 * <li><code>{@link Ext.form.Field#validateOnBlur validateOnBlur}</code>,
693 * <code>{@link Ext.form.Field#validationDelay validationDelay}</code>, and
694 * <code>{@link Ext.form.Field#validationEvent validationEvent}</code> : modify how/when validation is triggered</li>
699 * Creates a new TextField
700 * @param {Object} config Configuration options
703 Ext.form.TextField = Ext.extend(Ext.form.Field, {
705 * @cfg {String} vtypeText A custom error message to display in place of the default message provided
706 * for the <b><code>{@link #vtype}</code></b> currently set for this field (defaults to <tt>''</tt>). <b>Note</b>:
707 * only applies if <b><code>{@link #vtype}</code></b> is set, else ignored.
710 * @cfg {RegExp} stripCharsRe A JavaScript RegExp object used to strip unwanted content from the value
711 * before validation (defaults to <tt>null</tt>).
714 * @cfg {Boolean} grow <tt>true</tt> if this field should automatically grow and shrink to its content
715 * (defaults to <tt>false</tt>)
719 * @cfg {Number} growMin The minimum width to allow when <code><b>{@link #grow}</b> = true</code> (defaults
724 * @cfg {Number} growMax The maximum width to allow when <code><b>{@link #grow}</b> = true</code> (defaults
729 * @cfg {String} vtype A validation type name as defined in {@link Ext.form.VTypes} (defaults to <tt>null</tt>)
733 * @cfg {RegExp} maskRe An input mask regular expression that will be used to filter keystrokes that do
734 * not match (defaults to <tt>null</tt>)
738 * @cfg {Boolean} disableKeyFilter Specify <tt>true</tt> to disable input keystroke filtering (defaults
741 disableKeyFilter : false,
743 * @cfg {Boolean} allowBlank Specify <tt>false</tt> to validate that the value's length is > 0 (defaults to
748 * @cfg {Number} minLength Minimum input field length required (defaults to <tt>0</tt>)
752 * @cfg {Number} maxLength Maximum input field length allowed by validation (defaults to Number.MAX_VALUE).
753 * This behavior is intended to provide instant feedback to the user by improving usability to allow pasting
754 * and editing or overtyping and back tracking. To restrict the maximum number of characters that can be
755 * entered into the field use <tt><b>{@link Ext.form.Field#autoCreate autoCreate}</b></tt> to add
756 * any attributes you want to a field, for example:<pre><code>
757 var myField = new Ext.form.NumberField({
760 fieldLabel: 'Mobile',
761 maxLength: 16, // for validation
762 autoCreate: {tag: 'input', type: 'text', size: '20', autocomplete: 'off', maxlength: '10'}
766 maxLength : Number.MAX_VALUE,
768 * @cfg {String} minLengthText Error text to display if the <b><tt>{@link #minLength minimum length}</tt></b>
769 * validation fails (defaults to <tt>'The minimum length for this field is {minLength}'</tt>)
771 minLengthText : 'The minimum length for this field is {0}',
773 * @cfg {String} maxLengthText Error text to display if the <b><tt>{@link #maxLength maximum length}</tt></b>
774 * validation fails (defaults to <tt>'The maximum length for this field is {maxLength}'</tt>)
776 maxLengthText : 'The maximum length for this field is {0}',
778 * @cfg {Boolean} selectOnFocus <tt>true</tt> to automatically select any existing field text when the field
779 * receives input focus (defaults to <tt>false</tt>)
781 selectOnFocus : false,
783 * @cfg {String} blankText The error text to display if the <b><tt>{@link #allowBlank}</tt></b> validation
784 * fails (defaults to <tt>'This field is required'</tt>)
786 blankText : 'This field is required',
788 * @cfg {Function} validator A custom validation function to be called during field validation
789 * (defaults to <tt>null</tt>). If specified, this function will be called first, allowing the
790 * developer to override the default validation process. This function will be passed the current
791 * field value and expected to return boolean <tt>true</tt> if the value is valid or a string
792 * error message if invalid.
796 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation
797 * (defaults to <tt>null</tt>). If the test fails, the field will be marked invalid using
798 * <b><tt>{@link #regexText}</tt></b>.
802 * @cfg {String} regexText The error text to display if <b><tt>{@link #regex}</tt></b> is used and the
803 * test fails during validation (defaults to <tt>''</tt>)
807 * @cfg {String} emptyText The default text to place into an empty field (defaults to <tt>null</tt>).
808 * <b>Note</b>: that this value will be submitted to the server if this field is enabled and configured
809 * with a {@link #name}.
813 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the <b><tt>{@link #emptyText}</tt></b>
814 * (defaults to <tt>'x-form-empty-field'</tt>). This class is automatically added and removed as needed
815 * depending on the current field value.
817 emptyClass : 'x-form-empty-field',
820 * @cfg {Boolean} enableKeyEvents <tt>true</tt> to enable the proxying of key events for the HTML input
821 * field (defaults to <tt>false</tt>)
824 initComponent : function(){
825 Ext.form.TextField.superclass.initComponent.call(this);
829 * Fires when the <tt><b>{@link #autoSize}</b></tt> function is triggered. The field may or
830 * may not have actually changed size according to the default logic, but this event provides
831 * a hook for the developer to apply additional logic at runtime to resize the field if needed.
832 * @param {Ext.form.Field} this This text field
833 * @param {Number} width The new field width
839 * Keydown input field event. This event only fires if <tt><b>{@link #enableKeyEvents}</b></tt>
841 * @param {Ext.form.TextField} this This text field
842 * @param {Ext.EventObject} e
847 * Keyup input field event. This event only fires if <tt><b>{@link #enableKeyEvents}</b></tt>
849 * @param {Ext.form.TextField} this This text field
850 * @param {Ext.EventObject} e
855 * Keypress input field event. This event only fires if <tt><b>{@link #enableKeyEvents}</b></tt>
857 * @param {Ext.form.TextField} this This text field
858 * @param {Ext.EventObject} e
865 initEvents : function(){
866 Ext.form.TextField.superclass.initEvents.call(this);
867 if(this.validationEvent == 'keyup'){
868 this.validationTask = new Ext.util.DelayedTask(this.validate, this);
869 this.mon(this.el, 'keyup', this.filterValidation, this);
871 else if(this.validationEvent !== false){
872 this.mon(this.el, this.validationEvent, this.validate, this, {buffer: this.validationDelay});
874 if(this.selectOnFocus || this.emptyText){
875 this.on('focus', this.preFocus, this);
877 this.mon(this.el, 'mousedown', function(){
879 this.el.on('mouseup', function(e){
881 }, this, {single:true});
886 this.on('blur', this.postBlur, this);
887 this.applyEmptyText();
890 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Ext.form.VTypes[this.vtype+'Mask']))){
891 this.mon(this.el, 'keypress', this.filterKeys, this);
894 this.mon(this.el, 'keyup', this.onKeyUpBuffered, this, {buffer: 50});
895 this.mon(this.el, 'click', this.autoSize, this);
897 if(this.enableKeyEvents){
898 this.mon(this.el, 'keyup', this.onKeyUp, this);
899 this.mon(this.el, 'keydown', this.onKeyDown, this);
900 this.mon(this.el, 'keypress', this.onKeyPress, this);
904 processValue : function(value){
905 if(this.stripCharsRe){
906 var newValue = value.replace(this.stripCharsRe, '');
907 if(newValue !== value){
908 this.setRawValue(newValue);
915 filterValidation : function(e){
916 if(!e.isNavKeyPress()){
917 this.validationTask.delay(this.validationDelay);
922 onDisable: function(){
923 Ext.form.TextField.superclass.onDisable.call(this);
925 this.el.dom.unselectable = 'on';
930 onEnable: function(){
931 Ext.form.TextField.superclass.onEnable.call(this);
933 this.el.dom.unselectable = '';
938 onKeyUpBuffered : function(e){
939 if(!e.isNavKeyPress()){
945 onKeyUp : function(e){
946 this.fireEvent('keyup', this, e);
950 onKeyDown : function(e){
951 this.fireEvent('keydown', this, e);
955 onKeyPress : function(e){
956 this.fireEvent('keypress', this, e);
960 * Resets the current field value to the originally-loaded value and clears any validation messages.
961 * Also adds <tt><b>{@link #emptyText}</b></tt> and <tt><b>{@link #emptyClass}</b></tt> if the
962 * original value was blank.
965 Ext.form.TextField.superclass.reset.call(this);
966 this.applyEmptyText();
969 applyEmptyText : function(){
970 if(this.rendered && this.emptyText && this.getRawValue().length < 1 && !this.hasFocus){
971 this.setRawValue(this.emptyText);
972 this.el.addClass(this.emptyClass);
977 preFocus : function(){
980 if(el.dom.value == this.emptyText){
981 this.setRawValue('');
983 el.removeClass(this.emptyClass);
985 if(this.selectOnFocus){
988 }).defer(this.inEditor && Ext.isIE ? 50 : 0);
993 postBlur : function(){
994 this.applyEmptyText();
998 filterKeys : function(e){
999 // special keys don't generate charCodes, so leave them alone
1000 if(e.ctrlKey || e.isSpecialKey()){
1004 if(!this.maskRe.test(String.fromCharCode(e.getCharCode()))){
1009 setValue : function(v){
1010 if(this.emptyText && this.el && !Ext.isEmpty(v)){
1011 this.el.removeClass(this.emptyClass);
1013 Ext.form.TextField.superclass.setValue.apply(this, arguments);
1014 this.applyEmptyText();
1020 * Validates a value according to the field's validation rules and marks the field as invalid
1021 * if the validation fails
1022 * @param {Mixed} value The value to validate
1023 * @return {Boolean} True if the value is valid, else false
1025 validateValue : function(value){
1026 if(Ext.isFunction(this.validator)){
1027 var msg = this.validator(value);
1029 this.markInvalid(msg);
1033 if(value.length < 1 || value === this.emptyText){ // if it's blank
1034 if(this.allowBlank){
1035 this.clearInvalid();
1038 this.markInvalid(this.blankText);
1042 if(value.length < this.minLength){
1043 this.markInvalid(String.format(this.minLengthText, this.minLength));
1046 if(value.length > this.maxLength){
1047 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
1051 var vt = Ext.form.VTypes;
1052 if(!vt[this.vtype](value, this)){
1053 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
1057 if(this.regex && !this.regex.test(value)){
1058 this.markInvalid(this.regexText);
1065 * Selects text in this field
1066 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
1067 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
1069 selectText : function(start, end){
1070 var v = this.getRawValue();
1071 var doFocus = false;
1073 start = start === undefined ? 0 : start;
1074 end = end === undefined ? v.length : end;
1075 var d = this.el.dom;
1076 if(d.setSelectionRange){
1077 d.setSelectionRange(start, end);
1078 }else if(d.createTextRange){
1079 var range = d.createTextRange();
1080 range.moveStart('character', start);
1081 range.moveEnd('character', end-v.length);
1084 doFocus = Ext.isGecko || Ext.isOpera;
1094 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
1095 * This only takes effect if <tt><b>{@link #grow}</b> = true</tt>, and fires the {@link #autosize} event.
1097 autoSize : function(){
1098 if(!this.grow || !this.rendered){
1102 this.metrics = Ext.util.TextMetrics.createInstance(this.el);
1105 var v = el.dom.value;
1106 var d = document.createElement('div');
1107 d.appendChild(document.createTextNode(v));
1112 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
1113 this.el.setWidth(w);
1114 this.fireEvent('autosize', this, w);
1117 onDestroy: function(){
1118 if(this.validationTask){
1119 this.validationTask.cancel();
1120 this.validationTask = null;
1122 Ext.form.TextField.superclass.onDestroy.call(this);
1125 Ext.reg('textfield', Ext.form.TextField);
1127 * @class Ext.form.TriggerField
1128 * @extends Ext.form.TextField
1129 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
1130 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
1131 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
1132 * for which you can provide a custom implementation. For example:
1134 var trigger = new Ext.form.TriggerField();
1135 trigger.onTriggerClick = myTriggerFn;
1136 trigger.applyToMarkup('my-field');
1139 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
1140 * {@link Ext.form.DateField} and {@link Ext.form.ComboBox} are perfect examples of this.
1143 * Create a new TriggerField.
1144 * @param {Object} config Configuration options (valid {@Ext.form.TextField} config options will also be applied
1145 * to the base TextField)
1148 Ext.form.TriggerField = Ext.extend(Ext.form.TextField, {
1150 * @cfg {String} triggerClass
1151 * An additional CSS class used to style the trigger button. The trigger will always get the
1152 * class <tt>'x-form-trigger'</tt> by default and <tt>triggerClass</tt> will be <b>appended</b> if specified.
1155 * @cfg {Mixed} triggerConfig
1156 * <p>A {@link Ext.DomHelper DomHelper} config object specifying the structure of the
1157 * trigger element for this Field. (Optional).</p>
1158 * <p>Specify this when you need a customized element to act as the trigger button for a TriggerField.</p>
1159 * <p>Note that when using this option, it is the developer's responsibility to ensure correct sizing, positioning
1160 * and appearance of the trigger. Defaults to:</p>
1161 * <pre><code>{tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass}</code></pre>
1164 * @cfg {String/Object} autoCreate <p>A {@link Ext.DomHelper DomHelper} element spec, or true for a default
1165 * element spec. Used to create the {@link Ext.Component#getEl Element} which will encapsulate this Component.
1166 * See <tt>{@link Ext.Component#autoEl autoEl}</tt> for details. Defaults to:</p>
1167 * <pre><code>{tag: "input", type: "text", size: "16", autocomplete: "off"}</code></pre>
1169 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
1171 * @cfg {Boolean} hideTrigger <tt>true</tt> to hide the trigger element and display only the base
1172 * text field (defaults to <tt>false</tt>)
1176 * @cfg {Boolean} editable <tt>false</tt> to prevent the user from typing text directly into the field,
1177 * the field will only respond to a click on the trigger to set the value. (defaults to <tt>true</tt>)
1181 * @cfg {String} wrapFocusClass The class added to the to the wrap of the trigger element. Defaults to
1182 * <tt>x-trigger-wrap-focus</tt>.
1184 wrapFocusClass: 'x-trigger-wrap-focus',
1189 autoSize: Ext.emptyFn,
1200 onResize : function(w, h){
1201 Ext.form.TriggerField.superclass.onResize.call(this, w, h);
1202 if(typeof w == 'number'){
1203 this.el.setWidth(this.adjustWidth('input', w - this.trigger.getWidth()));
1205 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
1209 adjustSize : Ext.BoxComponent.prototype.adjustSize,
1212 getResizeEl : function(){
1217 getPositionEl : function(){
1222 alignErrorIcon : function(){
1224 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
1229 onRender : function(ct, position){
1230 Ext.form.TriggerField.superclass.onRender.call(this, ct, position);
1232 this.wrap = this.el.wrap({cls: 'x-form-field-wrap x-form-field-trigger-wrap'});
1233 this.trigger = this.wrap.createChild(this.triggerConfig ||
1234 {tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
1235 if(this.hideTrigger){
1236 this.trigger.setDisplayed(false);
1240 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
1243 this.editable = true;
1244 this.setEditable(false);
1248 afterRender : function(){
1249 Ext.form.TriggerField.superclass.afterRender.call(this);
1253 initTrigger : function(){
1254 this.mon(this.trigger, 'click', this.onTriggerClick, this, {preventDefault:true});
1255 this.trigger.addClassOnOver('x-form-trigger-over');
1256 this.trigger.addClassOnClick('x-form-trigger-click');
1260 onDestroy : function(){
1261 Ext.destroy(this.trigger, this.wrap);
1263 Ext.get(Ext.isIE ? document.body : document).un("mousedown", this.mimicBlur, this);
1265 Ext.form.TriggerField.superclass.onDestroy.call(this);
1269 onFocus : function(){
1270 Ext.form.TriggerField.superclass.onFocus.call(this);
1272 this.wrap.addClass(this.wrapFocusClass);
1273 this.mimicing = true;
1274 Ext.get(Ext.isIE ? document.body : document).on("mousedown", this.mimicBlur, this, {delay: 10});
1275 if(this.monitorTab){
1276 this.el.on('keydown', this.checkTab, this);
1282 checkTab : function(e){
1283 if(e.getKey() == e.TAB){
1289 onBlur : function(){
1294 mimicBlur : function(e){
1295 if(!this.wrap.contains(e.target) && this.validateBlur(e)){
1301 triggerBlur : function(){
1302 this.mimicing = false;
1303 Ext.get(Ext.isIE ? document.body : document).un("mousedown", this.mimicBlur, this);
1304 if(this.monitorTab && this.el){
1305 this.el.un("keydown", this.checkTab, this);
1307 Ext.form.TriggerField.superclass.onBlur.call(this);
1309 this.wrap.removeClass(this.wrapFocusClass);
1313 beforeBlur : Ext.emptyFn,
1316 * Allow or prevent the user from directly editing the field text. If false is passed,
1317 * the user will only be able to modify the field using the trigger. This method
1318 * is the runtime equivalent of setting the 'editable' config option at config time.
1319 * @param {Boolean} value True to allow the user to directly edit the field text
1321 setEditable : function(value){
1322 if(value == this.editable){
1325 this.editable = value;
1327 this.el.addClass('x-trigger-noedit').on('click', this.onTriggerClick, this).dom.setAttribute('readOnly', true);
1329 this.el.removeClass('x-trigger-noedit').un('click', this.onTriggerClick, this).dom.removeAttribute('readOnly');
1334 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
1335 validateBlur : function(e){
1340 * The function that should handle the trigger's click event. This method does nothing by default
1341 * until overridden by an implementing function. See Ext.form.ComboBox and Ext.form.DateField for
1342 * sample implementations.
1344 * @param {EventObject} e
1346 onTriggerClick : Ext.emptyFn
1349 * @cfg {Boolean} grow @hide
1352 * @cfg {Number} growMin @hide
1355 * @cfg {Number} growMax @hide
1360 * @class Ext.form.TwinTriggerField
1361 * @extends Ext.form.TriggerField
1362 * TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
1363 * to be extended by an implementing class. For an example of implementing this class, see the custom
1364 * SearchField implementation here:
1365 * <a href="http://extjs.com/deploy/ext/examples/form/custom.html">http://extjs.com/deploy/ext/examples/form/custom.html</a>
1367 Ext.form.TwinTriggerField = Ext.extend(Ext.form.TriggerField, {
1369 * @cfg {Mixed} triggerConfig
1370 * <p>A {@link Ext.DomHelper DomHelper} config object specifying the structure of the trigger elements
1371 * for this Field. (Optional).</p>
1372 * <p>Specify this when you need a customized element to contain the two trigger elements for this Field.
1373 * Each trigger element must be marked by the CSS class <tt>x-form-trigger</tt> (also see
1374 * <tt>{@link #trigger1Class}</tt> and <tt>{@link #trigger2Class}</tt>).</p>
1375 * <p>Note that when using this option, it is the developer's responsibility to ensure correct sizing,
1376 * positioning and appearance of the triggers.</p>
1379 * @cfg {String} trigger1Class
1380 * An additional CSS class used to style the trigger button. The trigger will always get the
1381 * class <tt>'x-form-trigger'</tt> by default and <tt>triggerClass</tt> will be <b>appended</b> if specified.
1384 * @cfg {String} trigger2Class
1385 * An additional CSS class used to style the trigger button. The trigger will always get the
1386 * class <tt>'x-form-trigger'</tt> by default and <tt>triggerClass</tt> will be <b>appended</b> if specified.
1389 initComponent : function(){
1390 Ext.form.TwinTriggerField.superclass.initComponent.call(this);
1392 this.triggerConfig = {
1393 tag:'span', cls:'x-form-twin-triggers', cn:[
1394 {tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
1395 {tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
1399 getTrigger : function(index){
1400 return this.triggers[index];
1403 initTrigger : function(){
1404 var ts = this.trigger.select('.x-form-trigger', true);
1405 this.wrap.setStyle('overflow', 'hidden');
1406 var triggerField = this;
1407 ts.each(function(t, all, index){
1408 t.hide = function(){
1409 var w = triggerField.wrap.getWidth();
1410 this.dom.style.display = 'none';
1411 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
1413 t.show = function(){
1414 var w = triggerField.wrap.getWidth();
1415 this.dom.style.display = '';
1416 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
1418 var triggerIndex = 'Trigger'+(index+1);
1420 if(this['hide'+triggerIndex]){
1421 t.dom.style.display = 'none';
1423 this.mon(t, 'click', this['on'+triggerIndex+'Click'], this, {preventDefault:true});
1424 t.addClassOnOver('x-form-trigger-over');
1425 t.addClassOnClick('x-form-trigger-click');
1427 this.triggers = ts.elements;
1431 * The function that should handle the trigger's click event. This method does nothing by default
1432 * until overridden by an implementing function. See {@link Ext.form.TriggerField#onTriggerClick}
1433 * for additional information.
1435 * @param {EventObject} e
1437 onTrigger1Click : Ext.emptyFn,
1439 * The function that should handle the trigger's click event. This method does nothing by default
1440 * until overridden by an implementing function. See {@link Ext.form.TriggerField#onTriggerClick}
1441 * for additional information.
1443 * @param {EventObject} e
1445 onTrigger2Click : Ext.emptyFn
1447 Ext.reg('trigger', Ext.form.TriggerField);/**
1448 * @class Ext.form.TextArea
1449 * @extends Ext.form.TextField
1450 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
1451 * support for auto-sizing.
1453 * Creates a new TextArea
1454 * @param {Object} config Configuration options
1457 Ext.form.TextArea = Ext.extend(Ext.form.TextField, {
1459 * @cfg {Number} growMin The minimum height to allow when <tt>{@link Ext.form.TextField#grow grow}=true</tt>
1460 * (defaults to <tt>60</tt>)
1464 * @cfg {Number} growMax The maximum height to allow when <tt>{@link Ext.form.TextField#grow grow}=true</tt>
1465 * (defaults to <tt>1000</tt>)
1468 growAppend : ' \n ',
1469 growPad : Ext.isWebKit ? -6 : 0,
1471 enterIsSpecial : false,
1474 * @cfg {Boolean} preventScrollbars <tt>true</tt> to prevent scrollbars from appearing regardless of how much text is
1475 * in the field (equivalent to setting overflow: hidden, defaults to <tt>false</tt>)
1477 preventScrollbars: false,
1479 * @cfg {String/Object} autoCreate <p>A {@link Ext.DomHelper DomHelper} element spec, or true for a default
1480 * element spec. Used to create the {@link Ext.Component#getEl Element} which will encapsulate this Component.
1481 * See <tt>{@link Ext.Component#autoEl autoEl}</tt> for details. Defaults to:</p>
1482 * <pre><code>{tag: "textarea", style: "width:100px;height:60px;", autocomplete: "off"}</code></pre>
1486 onRender : function(ct, position){
1488 this.defaultAutoCreate = {
1490 style:"width:100px;height:60px;",
1494 Ext.form.TextArea.superclass.onRender.call(this, ct, position);
1496 this.textSizeEl = Ext.DomHelper.append(document.body, {
1497 tag: "pre", cls: "x-form-grow-sizer"
1499 if(this.preventScrollbars){
1500 this.el.setStyle("overflow", "hidden");
1502 this.el.setHeight(this.growMin);
1506 onDestroy : function(){
1507 Ext.destroy(this.textSizeEl);
1508 Ext.form.TextArea.superclass.onDestroy.call(this);
1511 fireKey : function(e){
1512 if(e.isSpecialKey() && (this.enterIsSpecial || (e.getKey() != e.ENTER || e.hasModifier()))){
1513 this.fireEvent("specialkey", this, e);
1518 onKeyUp : function(e){
1519 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
1522 Ext.form.TextArea.superclass.onKeyUp.call(this, e);
1526 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
1527 * This only takes effect if grow = true, and fires the {@link #autosize} event if the height changes.
1529 autoSize: function(){
1530 if(!this.grow || !this.textSizeEl){
1534 var v = el.dom.value;
1535 var ts = this.textSizeEl;
1537 ts.appendChild(document.createTextNode(v));
1539 Ext.fly(ts).setWidth(this.el.getWidth());
1543 v += this.growAppend;
1545 v = v.replace(/\n/g, '<br />');
1549 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin) + this.growPad);
1550 if(h != this.lastHeight){
1551 this.lastHeight = h;
1552 this.el.setHeight(h);
1553 this.fireEvent("autosize", this, h);
1557 Ext.reg('textarea', Ext.form.TextArea);/**
1558 * @class Ext.form.NumberField
1559 * @extends Ext.form.TextField
1560 * Numeric text field that provides automatic keystroke filtering and numeric validation.
1562 * Creates a new NumberField
1563 * @param {Object} config Configuration options
1564 * @xtype numberfield
1566 Ext.form.NumberField = Ext.extend(Ext.form.TextField, {
1568 * @cfg {RegExp} stripCharsRe @hide
1571 * @cfg {RegExp} maskRe @hide
1574 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
1576 fieldClass: "x-form-field x-form-num-field",
1578 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
1580 allowDecimals : true,
1582 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
1584 decimalSeparator : ".",
1586 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
1588 decimalPrecision : 2,
1590 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
1592 allowNegative : true,
1594 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
1596 minValue : Number.NEGATIVE_INFINITY,
1598 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
1600 maxValue : Number.MAX_VALUE,
1602 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
1604 minText : "The minimum value for this field is {0}",
1606 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
1608 maxText : "The maximum value for this field is {0}",
1610 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
1611 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
1613 nanText : "{0} is not a valid number",
1615 * @cfg {String} baseChars The base set of characters to evaluate as valid numbers (defaults to '0123456789').
1617 baseChars : "0123456789",
1620 initEvents : function(){
1621 var allowed = this.baseChars + '';
1622 if (this.allowDecimals) {
1623 allowed += this.decimalSeparator;
1625 if (this.allowNegative) {
1628 this.maskRe = new RegExp('[' + Ext.escapeRe(allowed) + ']');
1629 Ext.form.NumberField.superclass.initEvents.call(this);
1633 validateValue : function(value){
1634 if(!Ext.form.NumberField.superclass.validateValue.call(this, value)){
1637 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
1640 value = String(value).replace(this.decimalSeparator, ".");
1642 this.markInvalid(String.format(this.nanText, value));
1645 var num = this.parseValue(value);
1646 if(num < this.minValue){
1647 this.markInvalid(String.format(this.minText, this.minValue));
1650 if(num > this.maxValue){
1651 this.markInvalid(String.format(this.maxText, this.maxValue));
1657 getValue : function(){
1658 return this.fixPrecision(this.parseValue(Ext.form.NumberField.superclass.getValue.call(this)));
1661 setValue : function(v){
1662 v = typeof v == 'number' ? v : parseFloat(String(v).replace(this.decimalSeparator, "."));
1663 v = isNaN(v) ? '' : String(v).replace(".", this.decimalSeparator);
1664 return Ext.form.NumberField.superclass.setValue.call(this, v);
1668 parseValue : function(value){
1669 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
1670 return isNaN(value) ? '' : value;
1674 fixPrecision : function(value){
1675 var nan = isNaN(value);
1676 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
1677 return nan ? '' : value;
1679 return parseFloat(parseFloat(value).toFixed(this.decimalPrecision));
1682 beforeBlur : function(){
1683 var v = this.parseValue(this.getRawValue());
1684 if(!Ext.isEmpty(v)){
1685 this.setValue(this.fixPrecision(v));
1689 Ext.reg('numberfield', Ext.form.NumberField);/**
1690 * @class Ext.form.DateField
1691 * @extends Ext.form.TriggerField
1692 * Provides a date input field with a {@link Ext.DatePicker} dropdown and automatic date validation.
1694 * Create a new DateField
1695 * @param {Object} config
1698 Ext.form.DateField = Ext.extend(Ext.form.TriggerField, {
1700 * @cfg {String} format
1701 * The default date format string which can be overriden for localization support. The format must be
1702 * valid according to {@link Date#parseDate} (defaults to <tt>'m/d/Y'</tt>).
1706 * @cfg {String} altFormats
1707 * Multiple date formats separated by "<tt>|</tt>" to try when parsing a user input value and it
1708 * does not match the defined format (defaults to
1709 * <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>).
1711 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",
1713 * @cfg {String} disabledDaysText
1714 * The tooltip to display when the date falls on a disabled day (defaults to <tt>'Disabled'</tt>)
1716 disabledDaysText : "Disabled",
1718 * @cfg {String} disabledDatesText
1719 * The tooltip text to display when the date falls on a disabled date (defaults to <tt>'Disabled'</tt>)
1721 disabledDatesText : "Disabled",
1723 * @cfg {String} minText
1724 * The error text to display when the date in the cell is before <tt>{@link #minValue}</tt> (defaults to
1725 * <tt>'The date in this field must be after {minValue}'</tt>).
1727 minText : "The date in this field must be equal to or after {0}",
1729 * @cfg {String} maxText
1730 * The error text to display when the date in the cell is after <tt>{@link #maxValue}</tt> (defaults to
1731 * <tt>'The date in this field must be before {maxValue}'</tt>).
1733 maxText : "The date in this field must be equal to or before {0}",
1735 * @cfg {String} invalidText
1736 * The error text to display when the date in the field is invalid (defaults to
1737 * <tt>'{value} is not a valid date - it must be in the format {format}'</tt>).
1739 invalidText : "{0} is not a valid date - it must be in the format {1}",
1741 * @cfg {String} triggerClass
1742 * An additional CSS class used to style the trigger button. The trigger will always get the
1743 * class <tt>'x-form-trigger'</tt> and <tt>triggerClass</tt> will be <b>appended</b> if specified
1744 * (defaults to <tt>'x-form-date-trigger'</tt> which displays a calendar icon).
1746 triggerClass : 'x-form-date-trigger',
1748 * @cfg {Boolean} showToday
1749 * <tt>false</tt> to hide the footer area of the DatePicker containing the Today button and disable
1750 * the keyboard handler for spacebar that selects the current date (defaults to <tt>true</tt>).
1754 * @cfg {Date/String} minValue
1755 * The minimum allowed date. Can be either a Javascript date object or a string date in a
1756 * valid format (defaults to null).
1759 * @cfg {Date/String} maxValue
1760 * The maximum allowed date. Can be either a Javascript date object or a string date in a
1761 * valid format (defaults to null).
1764 * @cfg {Array} disabledDays
1765 * An array of days to disable, 0 based (defaults to null). Some examples:<pre><code>
1766 // disable Sunday and Saturday:
1767 disabledDays: [0, 6]
1768 // disable weekdays:
1769 disabledDays: [1,2,3,4,5]
1773 * @cfg {Array} disabledDates
1774 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
1775 * expression so they are very powerful. Some examples:<pre><code>
1776 // disable these exact dates:
1777 disabledDates: ["03/08/2003", "09/16/2003"]
1778 // disable these days for every year:
1779 disabledDates: ["03/08", "09/16"]
1780 // only match the beginning (useful if you are using short years):
1781 disabledDates: ["^03/08"]
1782 // disable every day in March 2006:
1783 disabledDates: ["03/../2006"]
1784 // disable every day in every March:
1785 disabledDates: ["^03"]
1787 * Note that the format of the dates included in the array should exactly match the {@link #format} config.
1788 * In order to support regular expressions, if you are using a {@link #format date format} that has "." in
1789 * it, you will have to escape the dot when restricting dates. For example: <tt>["03\\.08\\.03"]</tt>.
1792 * @cfg {String/Object} autoCreate
1793 * A {@link Ext.DomHelper DomHelper element specification object}, or <tt>true</tt> for the default element
1794 * specification object:<pre><code>
1795 * autoCreate: {tag: "input", type: "text", size: "10", autocomplete: "off"}
1800 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
1802 initComponent : function(){
1803 Ext.form.DateField.superclass.initComponent.call(this);
1808 * Fires when a date is selected via the date picker.
1809 * @param {Ext.form.DateField} this
1810 * @param {Date} date The date that was selected
1815 if(Ext.isString(this.minValue)){
1816 this.minValue = this.parseDate(this.minValue);
1818 if(Ext.isString(this.maxValue)){
1819 this.maxValue = this.parseDate(this.maxValue);
1821 this.disabledDatesRE = null;
1822 this.initDisabledDays();
1826 initDisabledDays : function(){
1827 if(this.disabledDates){
1828 var dd = this.disabledDates,
1829 len = dd.length - 1,
1832 Ext.each(dd, function(d, i){
1833 re += Ext.isDate(d) ? '^' + Ext.escapeRe(d.dateFormat(this.format)) + '$' : dd[i];
1838 this.disabledDatesRE = new RegExp(re + ')');
1843 * Replaces any existing disabled dates with new values and refreshes the DatePicker.
1844 * @param {Array} disabledDates An array of date strings (see the <tt>{@link #disabledDates}</tt> config
1845 * for details on supported values) used to disable a pattern of dates.
1847 setDisabledDates : function(dd){
1848 this.disabledDates = dd;
1849 this.initDisabledDays();
1851 this.menu.picker.setDisabledDates(this.disabledDatesRE);
1856 * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker.
1857 * @param {Array} disabledDays An array of disabled day indexes. See the <tt>{@link #disabledDays}</tt>
1858 * config for details on supported values.
1860 setDisabledDays : function(dd){
1861 this.disabledDays = dd;
1863 this.menu.picker.setDisabledDays(dd);
1868 * Replaces any existing <tt>{@link #minValue}</tt> with the new value and refreshes the DatePicker.
1869 * @param {Date} value The minimum date that can be selected
1871 setMinValue : function(dt){
1872 this.minValue = (Ext.isString(dt) ? this.parseDate(dt) : dt);
1874 this.menu.picker.setMinDate(this.minValue);
1879 * Replaces any existing <tt>{@link #maxValue}</tt> with the new value and refreshes the DatePicker.
1880 * @param {Date} value The maximum date that can be selected
1882 setMaxValue : function(dt){
1883 this.maxValue = (Ext.isString(dt) ? this.parseDate(dt) : dt);
1885 this.menu.picker.setMaxDate(this.maxValue);
1890 validateValue : function(value){
1891 value = this.formatDate(value);
1892 if(!Ext.form.DateField.superclass.validateValue.call(this, value)){
1895 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
1899 value = this.parseDate(value);
1901 this.markInvalid(String.format(this.invalidText, svalue, this.format));
1904 var time = value.getTime();
1905 if(this.minValue && time < this.minValue.getTime()){
1906 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
1909 if(this.maxValue && time > this.maxValue.getTime()){
1910 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
1913 if(this.disabledDays){
1914 var day = value.getDay();
1915 for(var i = 0; i < this.disabledDays.length; i++) {
1916 if(day === this.disabledDays[i]){
1917 this.markInvalid(this.disabledDaysText);
1922 var fvalue = this.formatDate(value);
1923 if(this.disabledDatesRE && this.disabledDatesRE.test(fvalue)){
1924 this.markInvalid(String.format(this.disabledDatesText, fvalue));
1931 // Provides logic to override the default TriggerField.validateBlur which just returns true
1932 validateBlur : function(){
1933 return !this.menu || !this.menu.isVisible();
1937 * Returns the current date value of the date field.
1938 * @return {Date} The date value
1940 getValue : function(){
1941 return this.parseDate(Ext.form.DateField.superclass.getValue.call(this)) || "";
1945 * Sets the value of the date field. You can pass a date object or any string that can be
1946 * parsed into a valid date, using <tt>{@link #format}</tt> as the date format, according
1947 * to the same rules as {@link Date#parseDate} (the default format used is <tt>"m/d/Y"</tt>).
1950 //All of these calls set the same date value (May 4, 2006)
1952 //Pass a date object:
1953 var dt = new Date('5/4/2006');
1954 dateField.setValue(dt);
1956 //Pass a date string (default format):
1957 dateField.setValue('05/04/2006');
1959 //Pass a date string (custom format):
1960 dateField.format = 'Y-m-d';
1961 dateField.setValue('2006-05-04');
1963 * @param {String/Date} date The date or valid date string
1964 * @return {Ext.form.Field} this
1966 setValue : function(date){
1967 return Ext.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
1971 parseDate : function(value){
1972 if(!value || Ext.isDate(value)){
1975 var v = Date.parseDate(value, this.format);
1976 if(!v && this.altFormats){
1977 if(!this.altFormatsArray){
1978 this.altFormatsArray = this.altFormats.split("|");
1980 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
1981 v = Date.parseDate(value, this.altFormatsArray[i]);
1988 onDestroy : function(){
1989 Ext.destroy(this.menu);
1990 Ext.form.DateField.superclass.onDestroy.call(this);
1994 formatDate : function(date){
1995 return Ext.isDate(date) ? date.dateFormat(this.format) : date;
1999 * @method onTriggerClick
2003 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
2004 onTriggerClick : function(){
2008 if(this.menu == null){
2009 this.menu = new Ext.menu.DateMenu({
2014 Ext.apply(this.menu.picker, {
2015 minDate : this.minValue,
2016 maxDate : this.maxValue,
2017 disabledDatesRE : this.disabledDatesRE,
2018 disabledDatesText : this.disabledDatesText,
2019 disabledDays : this.disabledDays,
2020 disabledDaysText : this.disabledDaysText,
2021 format : this.format,
2022 showToday : this.showToday,
2023 minText : String.format(this.minText, this.formatDate(this.minValue)),
2024 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
2026 this.menu.picker.setValue(this.getValue() || new Date());
2027 this.menu.show(this.el, "tl-bl?");
2028 this.menuEvents('on');
2032 menuEvents: function(method){
2033 this.menu[method]('select', this.onSelect, this);
2034 this.menu[method]('hide', this.onMenuHide, this);
2035 this.menu[method]('show', this.onFocus, this);
2038 onSelect: function(m, d){
2040 this.fireEvent('select', this, d);
2044 onMenuHide: function(){
2045 this.focus(false, 60);
2046 this.menuEvents('un');
2050 beforeBlur : function(){
2051 var v = this.parseDate(this.getRawValue());
2058 * @cfg {Boolean} grow @hide
2061 * @cfg {Number} growMin @hide
2064 * @cfg {Number} growMax @hide
2071 Ext.reg('datefield', Ext.form.DateField);/**
\r
2072 * @class Ext.form.DisplayField
\r
2073 * @extends Ext.form.Field
\r
2074 * A display-only text field which is not validated and not submitted.
\r
2076 * Creates a new DisplayField.
\r
2077 * @param {Object} config Configuration options
\r
2078 * @xtype displayfield
\r
2080 Ext.form.DisplayField = Ext.extend(Ext.form.Field, {
\r
2081 validationEvent : false,
\r
2082 validateOnBlur : false,
\r
2083 defaultAutoCreate : {tag: "div"},
\r
2085 * @cfg {String} fieldClass The default CSS class for the field (defaults to <tt>"x-form-display-field"</tt>)
\r
2087 fieldClass : "x-form-display-field",
\r
2089 * @cfg {Boolean} htmlEncode <tt>false</tt> to skip HTML-encoding the text when rendering it (defaults to
\r
2090 * <tt>false</tt>). This might be useful if you want to include tags in the field's innerHTML rather than
\r
2091 * rendering them as string literals per the default logic.
\r
2093 htmlEncode: false,
\r
2096 initEvents : Ext.emptyFn,
\r
2098 isValid : function(){
\r
2102 validate : function(){
\r
2106 getRawValue : function(){
\r
2107 var v = this.rendered ? this.el.dom.innerHTML : Ext.value(this.value, '');
\r
2108 if(v === this.emptyText){
\r
2111 if(this.htmlEncode){
\r
2112 v = Ext.util.Format.htmlDecode(v);
\r
2117 getValue : function(){
\r
2118 return this.getRawValue();
\r
2121 getName: function() {
\r
2125 setRawValue : function(v){
\r
2126 if(this.htmlEncode){
\r
2127 v = Ext.util.Format.htmlEncode(v);
\r
2129 return this.rendered ? (this.el.dom.innerHTML = (Ext.isEmpty(v) ? '' : v)) : (this.value = v);
\r
2132 setValue : function(v){
\r
2133 this.setRawValue(v);
\r
2137 * @cfg {String} inputType
\r
2141 * @cfg {Boolean} disabled
\r
2145 * @cfg {Boolean} readOnly
\r
2149 * @cfg {Boolean} validateOnBlur
\r
2153 * @cfg {Number} validationDelay
\r
2157 * @cfg {String/Boolean} validationEvent
\r
2162 Ext.reg('displayfield', Ext.form.DisplayField);
\r
2164 * @class Ext.form.ComboBox
2165 * @extends Ext.form.TriggerField
2166 * <p>A combobox control with support for autocomplete, remote-loading, paging and many other features.</p>
2167 * <p>A ComboBox works in a similar manner to a traditional HTML <select> field. The difference is
2168 * that to submit the {@link #valueField}, you must specify a {@link #hiddenName} to create a hidden input
2169 * field to hold the value of the valueField. The <i>{@link #displayField}</i> is shown in the text field
2170 * which is named according to the {@link #name}.</p>
2171 * <p><b><u>Events</u></b></p>
2172 * <p>To do something when something in ComboBox is selected, configure the select event:<pre><code>
2173 var cb = new Ext.form.ComboBox({
2174 // all of your config options
2177 'select': yourFunction
2181 // Alternatively, you can assign events after the object is created:
2182 var cb = new Ext.form.ComboBox(yourOptions);
2183 cb.on('select', yourFunction, yourScope);
2186 * <p><b><u>ComboBox in Grid</u></b></p>
2187 * <p>If using a ComboBox in an {@link Ext.grid.EditorGridPanel Editor Grid} a {@link Ext.grid.Column#renderer renderer}
2188 * will be needed to show the displayField when the editor is not active. Set up the renderer manually, or implement
2189 * a reusable render, for example:<pre><code>
2190 // create reusable renderer
2191 Ext.util.Format.comboRenderer = function(combo){
2192 return function(value){
2193 var record = combo.findRecord(combo.{@link #valueField}, value);
2194 return record ? record.get(combo.{@link #displayField}) : combo.{@link #valueNotFoundText};
2198 // create the combo instance
2199 var combo = new Ext.form.ComboBox({
2200 {@link #typeAhead}: true,
2201 {@link #triggerAction}: 'all',
2202 {@link #lazyRender}:true,
2203 {@link #mode}: 'local',
2204 {@link #store}: new Ext.data.ArrayStore({
2210 data: [[1, 'item1'], [2, 'item2']]
2212 {@link #valueField}: 'myId',
2213 {@link #displayField}: 'displayText'
2216 // snippet of column model used within grid
2217 var cm = new Ext.grid.ColumnModel([{
2220 header: "Some Header",
2221 dataIndex: 'whatever',
2223 editor: combo, // specify reference to combo instance
2224 renderer: Ext.util.Format.comboRenderer(combo) // pass combo instance to reusable renderer
2230 * <p><b><u>Filtering</u></b></p>
2231 * <p>A ComboBox {@link #doQuery uses filtering itself}, for information about filtering the ComboBox
2232 * store manually see <tt>{@link #lastQuery}</tt>.</p>
2234 * Create a new ComboBox.
2235 * @param {Object} config Configuration options
2238 Ext.form.ComboBox = Ext.extend(Ext.form.TriggerField, {
2240 * @cfg {Mixed} transform The id, DOM node or element of an existing HTML SELECT to convert to a ComboBox.
2241 * Note that if you specify this and the combo is going to be in an {@link Ext.form.BasicForm} or
2242 * {@link Ext.form.FormPanel}, you must also set <tt>{@link #lazyRender} = true</tt>.
2245 * @cfg {Boolean} lazyRender <tt>true</tt> to prevent the ComboBox from rendering until requested
2246 * (should always be used when rendering into an {@link Ext.Editor} (e.g. {@link Ext.grid.EditorGridPanel Grids}),
2247 * defaults to <tt>false</tt>).
2250 * @cfg {String/Object} autoCreate <p>A {@link Ext.DomHelper DomHelper} element spec, or <tt>true</tt> for a default
2251 * element spec. Used to create the {@link Ext.Component#getEl Element} which will encapsulate this Component.
2252 * See <tt>{@link Ext.Component#autoEl autoEl}</tt> for details. Defaults to:</p>
2253 * <pre><code>{tag: "input", type: "text", size: "24", autocomplete: "off"}</code></pre>
2256 * @cfg {Ext.data.Store/Array} store The data source to which this combo is bound (defaults to <tt>undefined</tt>).
2257 * Acceptable values for this property are:
2258 * <div class="mdetail-params"><ul>
2259 * <li><b>any {@link Ext.data.Store Store} subclass</b></li>
2260 * <li><b>an Array</b> : Arrays will be converted to a {@link Ext.data.ArrayStore} internally.
2261 * <div class="mdetail-params"><ul>
2262 * <li><b>1-dimensional array</b> : (e.g., <tt>['Foo','Bar']</tt>)<div class="sub-desc">
2263 * A 1-dimensional array will automatically be expanded (each array item will be the combo
2264 * {@link #valueField value} and {@link #displayField text})</div></li>
2265 * <li><b>2-dimensional array</b> : (e.g., <tt>[['f','Foo'],['b','Bar']]</tt>)<div class="sub-desc">
2266 * For a multi-dimensional array, the value in index 0 of each item will be assumed to be the combo
2267 * {@link #valueField value}, while the value at index 1 is assumed to be the combo {@link #displayField text}.
2268 * </div></li></ul></div></li></ul></div>
2269 * <p>See also <tt>{@link #mode}</tt>.</p>
2272 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
2273 * the dropdown list (defaults to undefined, with no header element)
2277 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
2279 * @cfg {Number} listWidth The width (used as a parameter to {@link Ext.Element#setWidth}) of the dropdown
2280 * list (defaults to the width of the ComboBox field). See also <tt>{@link #minListWidth}
2283 * @cfg {String} displayField The underlying {@link Ext.data.Field#name data field name} to bind to this
2284 * ComboBox (defaults to undefined if <tt>{@link #mode} = 'remote'</tt> or <tt>'text'</tt> if
2285 * {@link #transform transforming a select} a select).
2286 * <p>See also <tt>{@link #valueField}</tt>.</p>
2287 * <p><b>Note</b>: if using a ComboBox in an {@link Ext.grid.EditorGridPanel Editor Grid} a
2288 * {@link Ext.grid.Column#renderer renderer} will be needed to show the displayField when the editor is not
2292 * @cfg {String} valueField The underlying {@link Ext.data.Field#name data value name} to bind to this
2293 * ComboBox (defaults to undefined if <tt>{@link #mode} = 'remote'</tt> or <tt>'value'</tt> if
2294 * {@link #transform transforming a select}).
2295 * <p><b>Note</b>: use of a <tt>valueField</tt> requires the user to make a selection in order for a value to be
2296 * mapped. See also <tt>{@link #hiddenName}</tt>, <tt>{@link #hiddenValue}</tt>, and <tt>{@link #displayField}</tt>.</p>
2299 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
2300 * field's data value (defaults to the underlying DOM element's name). Required for the combo's value to automatically
2301 * post during a form submission. See also {@link #valueField}.
2302 * <p><b>Note</b>: the hidden field's id will also default to this name if {@link #hiddenId} is not specified.
2303 * The ComboBox {@link Ext.Component#id id} and the <tt>{@link #hiddenId}</tt> <b>should be different</b>, since
2304 * no two DOM nodes should share the same id. So, if the ComboBox <tt>{@link Ext.form.Field#name name}</tt> and
2305 * <tt>hiddenName</tt> are the same, you should specify a unique <tt>{@link #hiddenId}</tt>.</p>
2308 * @cfg {String} hiddenId If <tt>{@link #hiddenName}</tt> is specified, <tt>hiddenId</tt> can also be provided
2309 * to give the hidden field a unique id (defaults to the <tt>{@link #hiddenName}</tt>). The <tt>hiddenId</tt>
2310 * and combo {@link Ext.Component#id id} should be different, since no two DOM
2311 * nodes should share the same id.
2314 * @cfg {String} hiddenValue Sets the initial value of the hidden field if {@link #hiddenName} is
2315 * specified to contain the selected {@link #valueField}, from the Store. Defaults to the configured
2316 * <tt>{@link Ext.form.Field#value value}</tt>.
2319 * @cfg {String} listClass The CSS class to add to the predefined <tt>'x-combo-list'</tt> class
2320 * applied the dropdown list element (defaults to '').
2324 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list
2325 * (defaults to <tt>'x-combo-selected'</tt>)
2327 selectedClass : 'x-combo-selected',
2329 * @cfg {String} listEmptyText The empty text to display in the data view if no items are found.
2334 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always
2335 * get the class <tt>'x-form-trigger'</tt> and <tt>triggerClass</tt> will be <b>appended</b> if specified
2336 * (defaults to <tt>'x-form-arrow-trigger'</tt> which displays a downward arrow icon).
2338 triggerClass : 'x-form-arrow-trigger',
2340 * @cfg {Boolean/String} shadow <tt>true</tt> or <tt>"sides"</tt> for the default effect, <tt>"frame"</tt> for
2341 * 4-way shadow, and <tt>"drop"</tt> for bottom-right
2345 * @cfg {String} listAlign A valid anchor position value. See <tt>{@link Ext.Element#alignTo}</tt> for details
2346 * on supported anchor positions (defaults to <tt>'tl-bl?'</tt>)
2348 listAlign : 'tl-bl?',
2350 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown
2351 * (defaults to <tt>300</tt>)
2355 * @cfg {Number} minHeight The minimum height in pixels of the dropdown list when the list is constrained by its
2356 * distance to the viewport edges (defaults to <tt>90</tt>)
2360 * @cfg {String} triggerAction The action to execute when the trigger is clicked.
2361 * <div class="mdetail-params"><ul>
2362 * <li><b><tt>'query'</tt></b> : <b>Default</b>
2363 * <p class="sub-desc">{@link #doQuery run the query} using the {@link Ext.form.Field#getRawValue raw value}.</p></li>
2364 * <li><b><tt>'all'</tt></b> :
2365 * <p class="sub-desc">{@link #doQuery run the query} specified by the <tt>{@link #allQuery}</tt> config option</p></li>
2367 * <p>See also <code>{@link #queryParam}</code>.</p>
2369 triggerAction : 'query',
2371 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and
2372 * {@link #typeAhead} activate (defaults to <tt>4</tt> if <tt>{@link #mode} = 'remote'</tt> or <tt>0</tt> if
2373 * <tt>{@link #mode} = 'local'</tt>, does not apply if
2374 * <tt>{@link Ext.form.TriggerField#editable editable} = false</tt>).
2378 * @cfg {Boolean} typeAhead <tt>true</tt> to populate and autoselect the remainder of the text being
2379 * typed after a configurable delay ({@link #typeAheadDelay}) if it matches a known value (defaults
2380 * to <tt>false</tt>)
2384 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and
2385 * sending the query to filter the dropdown list (defaults to <tt>500</tt> if <tt>{@link #mode} = 'remote'</tt>
2386 * or <tt>10</tt> if <tt>{@link #mode} = 'local'</tt>)
2390 * @cfg {Number} pageSize If greater than <tt>0</tt>, a {@link Ext.PagingToolbar} is displayed in the
2391 * footer of the dropdown list and the {@link #doQuery filter queries} will execute with page start and
2392 * {@link Ext.PagingToolbar#pageSize limit} parameters. Only applies when <tt>{@link #mode} = 'remote'</tt>
2393 * (defaults to <tt>0</tt>).
2397 * @cfg {Boolean} selectOnFocus <tt>true</tt> to select any existing text in the field immediately on focus.
2398 * Only applies when <tt>{@link Ext.form.TriggerField#editable editable} = true</tt> (defaults to
2401 selectOnFocus : false,
2403 * @cfg {String} queryParam Name of the query ({@link Ext.data.Store#baseParam baseParam} name for the store)
2404 * as it will be passed on the querystring (defaults to <tt>'query'</tt>)
2406 queryParam : 'query',
2408 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
2409 * when <tt>{@link #mode} = 'remote'</tt> (defaults to <tt>'Loading...'</tt>)
2411 loadingText : 'Loading...',
2413 * @cfg {Boolean} resizable <tt>true</tt> to add a resize handle to the bottom of the dropdown list
2414 * (creates an {@link Ext.Resizable} with 'se' {@link Ext.Resizable#pinned pinned} handles).
2415 * Defaults to <tt>false</tt>.
2419 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if
2420 * <tt>{@link #resizable} = true</tt> (defaults to <tt>8</tt>)
2424 * @cfg {String} allQuery The text query to send to the server to return all records for the list
2425 * with no filtering (defaults to '')
2429 * @cfg {String} mode Acceptable values are:
2430 * <div class="mdetail-params"><ul>
2431 * <li><b><tt>'remote'</tt></b> : <b>Default</b>
2432 * <p class="sub-desc">Automatically loads the <tt>{@link #store}</tt> the <b>first</b> time the trigger
2433 * is clicked. If you do not want the store to be automatically loaded the first time the trigger is
2434 * clicked, set to <tt>'local'</tt> and manually load the store. To force a requery of the store
2435 * <b>every</b> time the trigger is clicked see <tt>{@link #lastQuery}</tt>.</p></li>
2436 * <li><b><tt>'local'</tt></b> :
2437 * <p class="sub-desc">ComboBox loads local data</p>
2439 var combo = new Ext.form.ComboBox({
2440 renderTo: document.body,
2442 store: new Ext.data.ArrayStore({
2445 'myId', // numeric value is the key
2448 data: [[1, 'item1'], [2, 'item2']] // data is local
2451 displayField: 'displayText',
2452 triggerAction: 'all'
2454 * </code></pre></li>
2459 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to <tt>70</tt>, will
2460 * be ignored if <tt>{@link #listWidth}</tt> has a higher value)
2464 * @cfg {Boolean} forceSelection <tt>true</tt> to restrict the selected value to one of the values in the list,
2465 * <tt>false</tt> to allow the user to set arbitrary text into the field (defaults to <tt>false</tt>)
2467 forceSelection : false,
2469 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
2470 * if <tt>{@link #typeAhead} = true</tt> (defaults to <tt>250</tt>)
2472 typeAheadDelay : 250,
2474 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
2475 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined). If this
2476 * default text is used, it means there is no value set and no validation will occur on this field.
2480 * @cfg {Boolean} lazyInit <tt>true</tt> to not initialize the list for this combo until the field is focused
2481 * (defaults to <tt>true</tt>)
2486 * The value of the match string used to filter the store. Delete this property to force a requery.
2489 var combo = new Ext.form.ComboBox({
2494 // delete the previous query in the beforequery event or set
2495 // combo.lastQuery = null (this will reload the store the next time it expands)
2496 beforequery: function(qe){
2497 delete qe.combo.lastQuery;
2502 * To make sure the filter in the store is not cleared the first time the ComboBox trigger is used
2503 * configure the combo with <tt>lastQuery=''</tt>. Example use:
2505 var combo = new Ext.form.ComboBox({
2508 triggerAction: 'all',
2512 * @property lastQuery
2517 initComponent : function(){
2518 Ext.form.ComboBox.superclass.initComponent.call(this);
2522 * Fires when the dropdown list is expanded
2523 * @param {Ext.form.ComboBox} combo This combo box
2528 * Fires when the dropdown list is collapsed
2529 * @param {Ext.form.ComboBox} combo This combo box
2533 * @event beforeselect
2534 * Fires before a list item is selected. Return false to cancel the selection.
2535 * @param {Ext.form.ComboBox} combo This combo box
2536 * @param {Ext.data.Record} record The data record returned from the underlying store
2537 * @param {Number} index The index of the selected item in the dropdown list
2542 * Fires when a list item is selected
2543 * @param {Ext.form.ComboBox} combo This combo box
2544 * @param {Ext.data.Record} record The data record returned from the underlying store
2545 * @param {Number} index The index of the selected item in the dropdown list
2549 * @event beforequery
2550 * Fires before all queries are processed. Return false to cancel the query or set the queryEvent's
2551 * cancel property to true.
2552 * @param {Object} queryEvent An object that has these properties:<ul>
2553 * <li><code>combo</code> : Ext.form.ComboBox <div class="sub-desc">This combo box</div></li>
2554 * <li><code>query</code> : String <div class="sub-desc">The query</div></li>
2555 * <li><code>forceAll</code> : Boolean <div class="sub-desc">True to force "all" query</div></li>
2556 * <li><code>cancel</code> : Boolean <div class="sub-desc">Set to true to cancel the query</div></li>
2562 var s = Ext.getDom(this.transform);
2563 if(!this.hiddenName){
2564 this.hiddenName = s.name;
2567 this.mode = 'local';
2568 var d = [], opts = s.options;
2569 for(var i = 0, len = opts.length;i < len; i++){
2571 value = (o.hasAttribute ? o.hasAttribute('value') : o.getAttributeNode('value').specified) ? o.value : o.text;
2572 if(o.selected && Ext.isEmpty(this.value, true)) {
2575 d.push([value, o.text]);
2577 this.store = new Ext.data.ArrayStore({
2579 fields: ['value', 'text'],
2583 this.valueField = 'value';
2584 this.displayField = 'text';
2586 s.name = Ext.id(); // wipe out the name in case somewhere else they have a reference
2587 if(!this.lazyRender){
2589 this.el = Ext.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
2590 this.render(this.el.parentNode, s);
2591 Ext.removeNode(s); // remove it
2593 Ext.removeNode(s); // remove it
2596 //auto-configure store from local array data
2597 else if(this.store){
2598 this.store = Ext.StoreMgr.lookup(this.store);
2599 if(this.store.autoCreated){
2600 this.displayField = this.valueField = 'field1';
2601 if(!this.store.expandData){
2602 this.displayField = 'field2';
2604 this.mode = 'local';
2608 this.selectedIndex = -1;
2609 if(this.mode == 'local'){
2610 if(!Ext.isDefined(this.initialConfig.queryDelay)){
2611 this.queryDelay = 10;
2613 if(!Ext.isDefined(this.initialConfig.minChars)){
2620 onRender : function(ct, position){
2621 Ext.form.ComboBox.superclass.onRender.call(this, ct, position);
2622 if(this.hiddenName){
2623 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName,
2624 id: (this.hiddenId||this.hiddenName)}, 'before', true);
2626 // prevent input submission
2627 this.el.dom.removeAttribute('name');
2630 this.el.dom.setAttribute('autocomplete', 'off');
2636 this.on('focus', this.initList, this, {single: true});
2641 initValue : function(){
2642 Ext.form.ComboBox.superclass.initValue.call(this);
2643 if(this.hiddenField){
2644 this.hiddenField.value =
2645 Ext.isDefined(this.hiddenValue) ? this.hiddenValue :
2646 Ext.isDefined(this.value) ? this.value : '';
2651 initList : function(){
2653 var cls = 'x-combo-list';
2655 this.list = new Ext.Layer({
2656 parentEl: this.getListParent(),
2657 shadow: this.shadow,
2658 cls: [cls, this.listClass].join(' '),
2662 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
2663 this.list.setSize(lw, 0);
2664 this.list.swallowEvent('mousewheel');
2665 this.assetHeight = 0;
2666 if(this.syncFont !== false){
2667 this.list.setStyle('font-size', this.el.getStyle('font-size'));
2670 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
2671 this.assetHeight += this.header.getHeight();
2674 this.innerList = this.list.createChild({cls:cls+'-inner'});
2675 this.mon(this.innerList, 'mouseover', this.onViewOver, this);
2676 this.mon(this.innerList, 'mousemove', this.onViewMove, this);
2677 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
2680 this.footer = this.list.createChild({cls:cls+'-ft'});
2681 this.pageTb = new Ext.PagingToolbar({
2683 pageSize: this.pageSize,
2684 renderTo:this.footer
2686 this.assetHeight += this.footer.getHeight();
2691 * @cfg {String/Ext.XTemplate} tpl <p>The template string, or {@link Ext.XTemplate} instance to
2692 * use to display each item in the dropdown list. The dropdown list is displayed in a
2693 * DataView. See {@link #view}.</p>
2694 * <p>The default template string is:</p><pre><code>
2695 '<tpl for="."><div class="x-combo-list-item">{' + this.displayField + '}</div></tpl>'
2697 * <p>Override the default value to create custom UI layouts for items in the list.
2698 * For example:</p><pre><code>
2699 '<tpl for="."><div ext:qtip="{state}. {nick}" class="x-combo-list-item">{state}</div></tpl>'
2701 * <p>The template <b>must</b> contain one or more substitution parameters using field
2702 * names from the Combo's</b> {@link #store Store}. In the example above an
2703 * <pre>ext:qtip</pre> attribute is added to display other fields from the Store.</p>
2704 * <p>To preserve the default visual look of list items, add the CSS class name
2705 * <pre>x-combo-list-item</pre> to the template's container element.</p>
2706 * <p>Also see {@link #itemSelector} for additional details.</p>
2708 this.tpl = '<tpl for="."><div class="'+cls+'-item">{' + this.displayField + '}</div></tpl>';
2710 * @cfg {String} itemSelector
2711 * <p>A simple CSS selector (e.g. div.some-class or span:first-child) that will be
2712 * used to determine what nodes the {@link #view Ext.DataView} which handles the dropdown
2713 * display will be working with.</p>
2714 * <p><b>Note</b>: this setting is <b>required</b> if a custom XTemplate has been
2715 * specified in {@link #tpl} which assigns a class other than <pre>'x-combo-list-item'</pre>
2716 * to dropdown list items</b>
2721 * The {@link Ext.DataView DataView} used to display the ComboBox's options.
2722 * @type Ext.DataView
2724 this.view = new Ext.DataView({
2725 applyTo: this.innerList,
2728 selectedClass: this.selectedClass,
2729 itemSelector: this.itemSelector || '.' + cls + '-item',
2730 emptyText: this.listEmptyText
2733 this.mon(this.view, 'click', this.onViewClick, this);
2735 this.bindStore(this.store, true);
2738 this.resizer = new Ext.Resizable(this.list, {
2739 pinned:true, handles:'se'
2741 this.mon(this.resizer, 'resize', function(r, w, h){
2742 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
2744 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
2745 this.restrictHeight();
2748 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
2754 * <p>Returns the element used to house this ComboBox's pop-up list. Defaults to the document body.</p>
2755 * A custom implementation may be provided as a configuration option if the floating list needs to be rendered
2756 * to a different Element. An example might be rendering the list inside a Menu so that clicking
2757 * the list does not hide the Menu:<pre><code>
2758 var store = new Ext.data.ArrayStore({
2760 fields: ['initials', 'fullname'],
2762 ['FF', 'Fred Flintstone'],
2763 ['BR', 'Barney Rubble']
2767 var combo = new Ext.form.ComboBox({
2769 displayField: 'fullname',
2770 emptyText: 'Select a name...',
2771 forceSelection: true,
2772 getListParent: function() {
2773 return this.el.up('.x-menu');
2775 iconCls: 'no-icon', //use iconCls if placing within menu to shift to right side of menu
2777 selectOnFocus: true,
2778 triggerAction: 'all',
2783 var menu = new Ext.menu.Menu({
2786 combo // A Field in a Menu
2791 getListParent : function() {
2792 return document.body;
2796 * Returns the store associated with this combo.
2797 * @return {Ext.data.Store} The store
2799 getStore : function(){
2804 bindStore : function(store, initial){
2805 if(this.store && !initial){
2806 this.store.un('beforeload', this.onBeforeLoad, this);
2807 this.store.un('load', this.onLoad, this);
2808 this.store.un('exception', this.collapse, this);
2809 if(this.store !== store && this.store.autoDestroy){
2810 this.store.destroy();
2815 this.view.bindStore(null);
2821 this.lastQuery = null;
2823 this.pageTb.bindStore(store);
2827 this.store = Ext.StoreMgr.lookup(store);
2830 beforeload: this.onBeforeLoad,
2832 exception: this.collapse
2836 this.view.bindStore(store);
2842 initEvents : function(){
2843 Ext.form.ComboBox.superclass.initEvents.call(this);
2845 this.keyNav = new Ext.KeyNav(this.el, {
2847 this.inKeyMode = true;
2851 "down" : function(e){
2852 if(!this.isExpanded()){
2853 this.onTriggerClick();
2855 this.inKeyMode = true;
2860 "enter" : function(e){
2862 this.delayedCheck = true;
2863 this.unsetDelayCheck.defer(10, this);
2866 "esc" : function(e){
2870 "tab" : function(e){
2871 this.onViewClick(false);
2877 doRelay : function(foo, bar, hname){
2878 if(hname == 'down' || this.scope.isExpanded()){
2879 return Ext.KeyNav.prototype.doRelay.apply(this, arguments);
2886 this.queryDelay = Math.max(this.queryDelay || 10,
2887 this.mode == 'local' ? 10 : 250);
2888 this.dqTask = new Ext.util.DelayedTask(this.initQuery, this);
2890 this.taTask = new Ext.util.DelayedTask(this.onTypeAhead, this);
2892 if(this.editable !== false && !this.enableKeyEvents){
2893 this.mon(this.el, 'keyup', this.onKeyUp, this);
2898 onDestroy : function(){
2900 this.dqTask.cancel();
2903 this.bindStore(null);
2910 Ext.form.ComboBox.superclass.onDestroy.call(this);
2914 unsetDelayCheck : function(){
2915 delete this.delayedCheck;
2919 fireKey : function(e){
2920 var fn = function(ev){
2921 if (ev.isNavKeyPress() && !this.isExpanded() && !this.delayedCheck) {
2922 this.fireEvent("specialkey", this, ev);
2925 //For some reason I can't track down, the events fire in a different order in webkit.
2926 //Need a slight delay here
2927 if(this.inEditor && Ext.isWebKit && e.getKey() == e.TAB){
2928 fn.defer(10, this, [new Ext.EventObjectImpl(e)]);
2935 onResize : function(w, h){
2936 Ext.form.ComboBox.superclass.onResize.apply(this, arguments);
2937 if(this.list && !Ext.isDefined(this.listWidth)){
2938 var lw = Math.max(w, this.minListWidth);
2939 this.list.setWidth(lw);
2940 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
2945 onEnable : function(){
2946 Ext.form.ComboBox.superclass.onEnable.apply(this, arguments);
2947 if(this.hiddenField){
2948 this.hiddenField.disabled = false;
2953 onDisable : function(){
2954 Ext.form.ComboBox.superclass.onDisable.apply(this, arguments);
2955 if(this.hiddenField){
2956 this.hiddenField.disabled = true;
2961 onBeforeLoad : function(){
2965 this.innerList.update(this.loadingText ?
2966 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
2967 this.restrictHeight();
2968 this.selectedIndex = -1;
2972 onLoad : function(){
2976 if(this.store.getCount() > 0){
2978 this.restrictHeight();
2979 if(this.lastQuery == this.allQuery){
2981 this.el.dom.select();
2983 if(!this.selectByValue(this.value, true)){
2984 this.select(0, true);
2988 if(this.typeAhead && this.lastKey != Ext.EventObject.BACKSPACE && this.lastKey != Ext.EventObject.DELETE){
2989 this.taTask.delay(this.typeAheadDelay);
2993 this.onEmptyResults();
2999 onTypeAhead : function(){
3000 if(this.store.getCount() > 0){
3001 var r = this.store.getAt(0);
3002 var newValue = r.data[this.displayField];
3003 var len = newValue.length;
3004 var selStart = this.getRawValue().length;
3005 if(selStart != len){
3006 this.setRawValue(newValue);
3007 this.selectText(selStart, newValue.length);
3013 onSelect : function(record, index){
3014 if(this.fireEvent('beforeselect', this, record, index) !== false){
3015 this.setValue(record.data[this.valueField || this.displayField]);
3017 this.fireEvent('select', this, record, index);
3022 getName: function(){
3023 var hf = this.hiddenField;
3024 return hf && hf.name ? hf.name : this.hiddenName || Ext.form.ComboBox.superclass.getName.call(this);
3028 * Returns the currently selected field value or empty string if no value is set.
3029 * @return {String} value The selected value
3031 getValue : function(){
3032 if(this.valueField){
3033 return Ext.isDefined(this.value) ? this.value : '';
3035 return Ext.form.ComboBox.superclass.getValue.call(this);
3040 * Clears any text/value currently set in the field
3042 clearValue : function(){
3043 if(this.hiddenField){
3044 this.hiddenField.value = '';
3046 this.setRawValue('');
3047 this.lastSelectionText = '';
3048 this.applyEmptyText();
3053 * Sets the specified value into the field. If the value finds a match, the corresponding record text
3054 * will be displayed in the field. If the value does not match the data value of an existing item,
3055 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
3056 * Otherwise the field will be blank (although the value will still be set).
3057 * @param {String} value The value to match
3058 * @return {Ext.form.Field} this
3060 setValue : function(v){
3062 if(this.valueField){
3063 var r = this.findRecord(this.valueField, v);
3065 text = r.data[this.displayField];
3066 }else if(Ext.isDefined(this.valueNotFoundText)){
3067 text = this.valueNotFoundText;
3070 this.lastSelectionText = text;
3071 if(this.hiddenField){
3072 this.hiddenField.value = v;
3074 Ext.form.ComboBox.superclass.setValue.call(this, text);
3080 findRecord : function(prop, value){
3082 if(this.store.getCount() > 0){
3083 this.store.each(function(r){
3084 if(r.data[prop] == value){
3094 onViewMove : function(e, t){
3095 this.inKeyMode = false;
3099 onViewOver : function(e, t){
3100 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
3103 var item = this.view.findItemFromChild(t);
3105 var index = this.view.indexOf(item);
3106 this.select(index, false);
3111 onViewClick : function(doFocus){
3112 var index = this.view.getSelectedIndexes()[0];
3113 var r = this.store.getAt(index);
3115 this.onSelect(r, index);
3117 if(doFocus !== false){
3123 restrictHeight : function(){
3124 this.innerList.dom.style.height = '';
3125 var inner = this.innerList.dom;
3126 var pad = this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight;
3127 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
3128 var ha = this.getPosition()[1]-Ext.getBody().getScroll().top;
3129 var hb = Ext.lib.Dom.getViewHeight()-ha-this.getSize().height;
3130 var space = Math.max(ha, hb, this.minHeight || 0)-this.list.shadowOffset-pad-5;
3131 h = Math.min(h, space, this.maxHeight);
3133 this.innerList.setHeight(h);
3134 this.list.beginUpdate();
3135 this.list.setHeight(h+pad);
3136 this.list.alignTo(this.wrap, this.listAlign);
3137 this.list.endUpdate();
3141 onEmptyResults : function(){
3146 * Returns true if the dropdown list is expanded, else false.
3148 isExpanded : function(){
3149 return this.list && this.list.isVisible();
3153 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
3154 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
3155 * @param {String} value The data value of the item to select
3156 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
3157 * selected item if it is not currently in view (defaults to true)
3158 * @return {Boolean} True if the value matched an item in the list, else false
3160 selectByValue : function(v, scrollIntoView){
3161 if(!Ext.isEmpty(v, true)){
3162 var r = this.findRecord(this.valueField || this.displayField, v);
3164 this.select(this.store.indexOf(r), scrollIntoView);
3172 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
3173 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
3174 * @param {Number} index The zero-based index of the list item to select
3175 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
3176 * selected item if it is not currently in view (defaults to true)
3178 select : function(index, scrollIntoView){
3179 this.selectedIndex = index;
3180 this.view.select(index);
3181 if(scrollIntoView !== false){
3182 var el = this.view.getNode(index);
3184 this.innerList.scrollChildIntoView(el, false);
3190 selectNext : function(){
3191 var ct = this.store.getCount();
3193 if(this.selectedIndex == -1){
3195 }else if(this.selectedIndex < ct-1){
3196 this.select(this.selectedIndex+1);
3202 selectPrev : function(){
3203 var ct = this.store.getCount();
3205 if(this.selectedIndex == -1){
3207 }else if(this.selectedIndex !== 0){
3208 this.select(this.selectedIndex-1);
3214 onKeyUp : function(e){
3216 if(this.editable !== false && (k == e.BACKSPACE || !e.isSpecialKey())){
3218 this.dqTask.delay(this.queryDelay);
3220 Ext.form.ComboBox.superclass.onKeyUp.call(this, e);
3224 validateBlur : function(){
3225 return !this.list || !this.list.isVisible();
3229 initQuery : function(){
3230 this.doQuery(this.getRawValue());
3234 beforeBlur : function(){
3235 var val = this.getRawValue();
3236 if(this.forceSelection){
3237 if(val.length > 0 && val != this.emptyText){
3238 this.el.dom.value = Ext.isDefined(this.lastSelectionText) ? this.lastSelectionText : '';
3239 this.applyEmptyText();
3244 var rec = this.findRecord(this.displayField, val);
3246 val = rec.get(this.valueField || this.displayField);
3253 * Execute a query to filter the dropdown list. Fires the {@link #beforequery} event prior to performing the
3254 * query allowing the query action to be canceled if needed.
3255 * @param {String} query The SQL query to execute
3256 * @param {Boolean} forceAll <tt>true</tt> to force the query to execute even if there are currently fewer
3257 * characters in the field than the minimum specified by the <tt>{@link #minChars}</tt> config option. It
3258 * also clears any filter previously saved in the current store (defaults to <tt>false</tt>)
3260 doQuery : function(q, forceAll){
3261 q = Ext.isEmpty(q) ? '' : q;
3268 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
3272 forceAll = qe.forceAll;
3273 if(forceAll === true || (q.length >= this.minChars)){
3274 if(this.lastQuery !== q){
3276 if(this.mode == 'local'){
3277 this.selectedIndex = -1;
3279 this.store.clearFilter();
3281 this.store.filter(this.displayField, q);
3285 this.store.baseParams[this.queryParam] = q;
3287 params: this.getParams(q)
3292 this.selectedIndex = -1;
3299 getParams : function(q){
3301 //p[this.queryParam] = q;
3304 p.limit = this.pageSize;
3310 * Hides the dropdown list if it is currently expanded. Fires the {@link #collapse} event on completion.
3312 collapse : function(){
3313 if(!this.isExpanded()){
3317 Ext.getDoc().un('mousewheel', this.collapseIf, this);
3318 Ext.getDoc().un('mousedown', this.collapseIf, this);
3319 this.fireEvent('collapse', this);
3323 collapseIf : function(e){
3324 if(!e.within(this.wrap) && !e.within(this.list)){
3330 * Expands the dropdown list if it is currently hidden. Fires the {@link #expand} event on completion.
3332 expand : function(){
3333 if(this.isExpanded() || !this.hasFocus){
3336 this.list.alignTo(this.wrap, this.listAlign);
3339 this.innerList.setOverflow('auto'); // necessary for FF 2.0/Mac
3343 mousewheel: this.collapseIf,
3344 mousedown: this.collapseIf
3346 this.fireEvent('expand', this);
3350 * @method onTriggerClick
3354 // Implements the default empty TriggerField.onTriggerClick function
3355 onTriggerClick : function(){
3359 if(this.isExpanded()){
3364 if(this.triggerAction == 'all') {
3365 this.doQuery(this.allQuery, true);
3367 this.doQuery(this.getRawValue());
3378 * @cfg {Boolean} grow @hide
3381 * @cfg {Number} growMin @hide
3384 * @cfg {Number} growMax @hide
3388 Ext.reg('combo', Ext.form.ComboBox);/**
3389 * @class Ext.form.Checkbox
3390 * @extends Ext.form.Field
3391 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
3393 * Creates a new Checkbox
3394 * @param {Object} config Configuration options
3397 Ext.form.Checkbox = Ext.extend(Ext.form.Field, {
3399 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
3401 focusClass : undefined,
3403 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to 'x-form-field')
3405 fieldClass : 'x-form-field',
3407 * @cfg {Boolean} checked <tt>true</tt> if the checkbox should render initially checked (defaults to <tt>false</tt>)
3411 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
3412 * {tag: 'input', type: 'checkbox', autocomplete: 'off'})
3414 defaultAutoCreate : { tag: 'input', type: 'checkbox', autocomplete: 'off'},
3416 * @cfg {String} boxLabel The text that appears beside the checkbox
3419 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
3422 * @cfg {Function} handler A function called when the {@link #checked} value changes (can be used instead of
3423 * handling the check event). The handler is passed the following parameters:
3424 * <div class="mdetail-params"><ul>
3425 * <li><b>checkbox</b> : Ext.form.Checkbox<div class="sub-desc">The Checkbox being toggled.</div></li>
3426 * <li><b>checked</b> : Boolean<div class="sub-desc">The new checked state of the checkbox.</div></li>
3430 * @cfg {Object} scope An object to use as the scope ('this' reference) of the {@link #handler} function
3431 * (defaults to this Checkbox).
3435 actionMode : 'wrap',
3438 initComponent : function(){
3439 Ext.form.Checkbox.superclass.initComponent.call(this);
3443 * Fires when the checkbox is checked or unchecked.
3444 * @param {Ext.form.Checkbox} this This checkbox
3445 * @param {Boolean} checked The new checked value
3452 onResize : function(){
3453 Ext.form.Checkbox.superclass.onResize.apply(this, arguments);
3454 if(!this.boxLabel && !this.fieldLabel){
3455 this.el.alignTo(this.wrap, 'c-c');
3460 initEvents : function(){
3461 Ext.form.Checkbox.superclass.initEvents.call(this);
3462 this.mon(this.el, 'click', this.onClick, this);
3463 this.mon(this.el, 'change', this.onClick, this);
3467 getResizeEl : function(){
3472 getPositionEl : function(){
3478 * Overridden and disabled. The editor element does not support standard valid/invalid marking.
3481 markInvalid : Ext.emptyFn,
3484 * Overridden and disabled. The editor element does not support standard valid/invalid marking.
3487 clearInvalid : Ext.emptyFn,
3490 onRender : function(ct, position){
3491 Ext.form.Checkbox.superclass.onRender.call(this, ct, position);
3492 if(this.inputValue !== undefined){
3493 this.el.dom.value = this.inputValue;
3495 this.wrap = this.el.wrap({cls: 'x-form-check-wrap'});
3497 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
3500 this.setValue(true);
3502 this.checked = this.el.dom.checked;
3507 onDestroy : function(){
3508 Ext.destroy(this.wrap);
3509 Ext.form.Checkbox.superclass.onDestroy.call(this);
3513 initValue : function() {
3514 this.originalValue = this.getValue();
3518 * Returns the checked state of the checkbox.
3519 * @return {Boolean} True if checked, else false
3521 getValue : function(){
3523 return this.el.dom.checked;
3529 onClick : function(){
3530 if(this.el.dom.checked != this.checked){
3531 this.setValue(this.el.dom.checked);
3536 * Sets the checked state of the checkbox, fires the 'check' event, and calls a
3537 * <code>{@link #handler}</code> (if configured).
3538 * @param {Boolean/String} checked The following values will check the checkbox:
3539 * <code>true, 'true', '1', or 'on'</code>. Any other value will uncheck the checkbox.
3540 * @return {Ext.form.Field} this
3542 setValue : function(v){
3543 var checked = this.checked ;
3544 this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
3546 this.el.dom.checked = this.checked;
3547 this.el.dom.defaultChecked = this.checked;
3549 if(checked != this.checked){
3550 this.fireEvent('check', this, this.checked);
3552 this.handler.call(this.scope || this, this, this.checked);
3558 Ext.reg('checkbox', Ext.form.Checkbox);
3560 * @class Ext.form.CheckboxGroup
3561 * @extends Ext.form.Field
3562 * <p>A grouping container for {@link Ext.form.Checkbox} controls.</p>
3563 * <p>Sample usage:</p>
3565 var myCheckboxGroup = new Ext.form.CheckboxGroup({
3567 xtype: 'checkboxgroup',
3568 fieldLabel: 'Single Column',
3569 itemCls: 'x-check-group-alt',
3570 // Put all controls in a single column with width 100%
3573 {boxLabel: 'Item 1', name: 'cb-col-1'},
3574 {boxLabel: 'Item 2', name: 'cb-col-2', checked: true},
3575 {boxLabel: 'Item 3', name: 'cb-col-3'}
3580 * Creates a new CheckboxGroup
3581 * @param {Object} config Configuration options
3582 * @xtype checkboxgroup
3584 Ext.form.CheckboxGroup = Ext.extend(Ext.form.Field, {
3586 * @cfg {Array} items An Array of {@link Ext.form.Checkbox Checkbox}es or Checkbox config objects
3587 * to arrange in the group.
3590 * @cfg {String/Number/Array} columns Specifies the number of columns to use when displaying grouped
3591 * checkbox/radio controls using automatic layout. This config can take several types of values:
3592 * <ul><li><b>'auto'</b> : <p class="sub-desc">The controls will be rendered one per column on one row and the width
3593 * of each column will be evenly distributed based on the width of the overall field container. This is the default.</p></li>
3594 * <li><b>Number</b> : <p class="sub-desc">If you specific a number (e.g., 3) that number of columns will be
3595 * created and the contained controls will be automatically distributed based on the value of {@link #vertical}.</p></li>
3596 * <li><b>Array</b> : Object<p class="sub-desc">You can also specify an array of column widths, mixing integer
3597 * (fixed width) and float (percentage width) values as needed (e.g., [100, .25, .75]). Any integer values will
3598 * be rendered first, then any float values will be calculated as a percentage of the remaining space. Float
3599 * values do not have to add up to 1 (100%) although if you want the controls to take up the entire field
3600 * container you should do so.</p></li></ul>
3604 * @cfg {Boolean} vertical True to distribute contained controls across columns, completely filling each column
3605 * top to bottom before starting on the next column. The number of controls in each column will be automatically
3606 * calculated to keep columns as even as possible. The default value is false, so that controls will be added
3607 * to columns one at a time, completely filling each row left to right before starting on the next row.
3611 * @cfg {Boolean} allowBlank False to validate that at least one item in the group is checked (defaults to true).
3612 * If no items are selected at validation time, {@link @blankText} will be used as the error text.
3616 * @cfg {String} blankText Error text to display if the {@link #allowBlank} validation fails (defaults to "You must
3617 * select at least one item in this group")
3619 blankText : "You must select at least one item in this group",
3622 defaultType : 'checkbox',
3625 groupCls : 'x-form-check-group',
3628 initComponent: function(){
3632 * Fires when the state of a child checkbox changes.
3633 * @param {Ext.form.CheckboxGroup} this
3634 * @param {Array} checked An array containing the checked boxes.
3638 Ext.form.CheckboxGroup.superclass.initComponent.call(this);
3642 onRender : function(ct, position){
3651 defaultType: this.defaultType,
3660 if(this.items[0].items){
3662 // The container has standard ColumnLayout configs, so pass them in directly
3664 Ext.apply(panelCfg, {
3665 layoutConfig: {columns: this.items.length},
3666 defaults: this.defaults,
3669 for(var i=0, len=this.items.length; i<len; i++){
3670 Ext.applyIf(this.items[i], colCfg);
3675 // The container has field item configs, so we have to generate the column
3676 // panels first then move the items into the columns as needed.
3678 var numCols, cols = [];
3680 if(typeof this.columns == 'string'){ // 'auto' so create a col per item
3681 this.columns = this.items.length;
3683 if(!Ext.isArray(this.columns)){
3685 for(var i=0; i<this.columns; i++){
3686 cs.push((100/this.columns)*.01); // distribute by even %
3691 numCols = this.columns.length;
3693 // Generate the column configs with the correct width setting
3694 for(var i=0; i<numCols; i++){
3695 var cc = Ext.apply({items:[]}, colCfg);
3696 cc[this.columns[i] <= 1 ? 'columnWidth' : 'width'] = this.columns[i];
3698 cc.defaults = Ext.apply(cc.defaults || {}, this.defaults)
3703 // Distribute the original items into the columns
3705 var rows = Math.ceil(this.items.length / numCols), ri = 0;
3706 for(var i=0, len=this.items.length; i<len; i++){
3707 if(i>0 && i%rows==0){
3710 if(this.items[i].fieldLabel){
3711 this.items[i].hideLabel = false;
3713 cols[ri].items.push(this.items[i]);
3716 for(var i=0, len=this.items.length; i<len; i++){
3717 var ci = i % numCols;
3718 if(this.items[i].fieldLabel){
3719 this.items[i].hideLabel = false;
3721 cols[ci].items.push(this.items[i]);
3725 Ext.apply(panelCfg, {
3726 layoutConfig: {columns: numCols},
3731 this.panel = new Ext.Panel(panelCfg);
3732 this.panel.ownerCt = this;
3733 this.el = this.panel.getEl();
3735 if(this.forId && this.itemCls){
3736 var l = this.el.up(this.itemCls).child('label', true);
3738 l.setAttribute('htmlFor', this.forId);
3742 var fields = this.panel.findBy(function(c){
3743 return c.isFormField;
3746 this.items = new Ext.util.MixedCollection();
3747 this.items.addAll(fields);
3749 Ext.form.CheckboxGroup.superclass.onRender.call(this, ct, position);
3752 afterRender : function(){
3753 Ext.form.CheckboxGroup.superclass.afterRender.call(this);
3755 this.setValue.apply(this, this.values);
3758 this.eachItem(function(item){
3759 item.on('check', this.fireChecked, this);
3760 item.inGroup = true;
3765 doLayout: function(){
3766 //ugly method required to layout hidden items
3768 this.panel.forceLayout = this.ownerCt.forceLayout;
3769 this.panel.doLayout();
3774 fireChecked: function(){
3776 this.eachItem(function(item){
3781 this.fireEvent('change', this, arr);
3785 validateValue : function(value){
3786 if(!this.allowBlank){
3788 this.eachItem(function(f){
3790 return (blank = false);
3794 this.markInvalid(this.blankText);
3802 onDisable : function(){
3803 this.eachItem(function(item){
3809 onEnable : function(){
3810 this.eachItem(function(item){
3816 doLayout: function(){
3818 this.panel.forceLayout = this.ownerCt.forceLayout;
3819 this.panel.doLayout();
3824 onResize : function(w, h){
3825 this.panel.setSize(w, h);
3826 this.panel.doLayout();
3829 // inherit docs from Field
3831 Ext.form.CheckboxGroup.superclass.reset.call(this);
3832 this.eachItem(function(c){
3840 * {@link Ext.form.Checkbox#setValue Set the value(s)} of an item or items
3841 * in the group. Examples illustrating how this method may be called:
3843 // call with name and value
3844 myCheckboxGroup.setValue('cb-col-1', true);
3845 // call with an array of boolean values
3846 myCheckboxGroup.setValue([true, false, false]);
3847 // call with an object literal specifying item:value pairs
3848 myCheckboxGroup.setValue({
3852 // use comma separated string to set items with name to true (checked)
3853 myCheckboxGroup.setValue('cb-col-1,cb-col-3');
3855 * See {@link Ext.form.Checkbox#setValue} for additional information.
3856 * @param {Mixed} id The checkbox to check, or as described by example shown.
3857 * @param {Boolean} value (optional) The value to set the item.
3858 * @return {Ext.form.CheckboxGroup} this
3860 setValue : function(id, value){
3862 if(arguments.length == 1){
3863 if(Ext.isArray(id)){
3864 //an array of boolean values
3865 Ext.each(id, function(val, idx){
3866 var item = this.items.itemAt(idx);
3871 }else if(Ext.isObject(id)){
3872 //set of name/value pairs
3874 var f = this.getBox(i);
3880 this.setValueForItem(id);
3883 var f = this.getBox(id);
3889 this.values = arguments;
3895 onDestroy: function(){
3896 Ext.destroy(this.panel);
3897 Ext.form.CheckboxGroup.superclass.onDestroy.call(this);
3901 setValueForItem : function(val){
3902 val = String(val).split(',');
3903 this.eachItem(function(item){
3904 if(val.indexOf(item.inputValue)> -1){
3905 item.setValue(true);
3911 getBox : function(id){
3913 this.eachItem(function(f){
3914 if(id == f || f.dataIndex == id || f.id == id || f.getName() == id){
3923 * Gets an array of the selected {@link Ext.form.Checkbox} in the group.
3924 * @return {Array} An array of the selected checkboxes.
3926 getValue : function(){
3928 this.eachItem(function(item){
3937 eachItem: function(fn){
3938 if(this.items && this.items.each){
3939 this.items.each(fn, this);
3944 * @cfg {String} name
3951 initValue : Ext.emptyFn,
3956 getValue : Ext.emptyFn,
3958 * @method getRawValue
3961 getRawValue : Ext.emptyFn,
3964 * @method setRawValue
3967 setRawValue : Ext.emptyFn
3971 Ext.reg('checkboxgroup', Ext.form.CheckboxGroup);
3973 * @class Ext.form.Radio
3974 * @extends Ext.form.Checkbox
3975 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
3976 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
3978 * Creates a new Radio
3979 * @param {Object} config Configuration options
3982 Ext.form.Radio = Ext.extend(Ext.form.Checkbox, {
3986 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
3989 markInvalid : Ext.emptyFn,
3991 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
3994 clearInvalid : Ext.emptyFn,
3997 * If this radio is part of a group, it will return the selected value
4000 getGroupValue : function(){
4001 var p = this.el.up('form') || Ext.getBody();
4002 var c = p.child('input[name='+this.el.dom.name+']:checked', true);
4003 return c ? c.value : null;
4007 onClick : function(){
4008 if(this.el.dom.checked != this.checked){
4009 var els = this.getCheckEl().select('input[name=' + this.el.dom.name + ']');
4010 els.each(function(el){
4011 if(el.dom.id == this.id){
4012 this.setValue(true);
4014 Ext.getCmp(el.dom.id).setValue(false);
4021 * Sets either the checked/unchecked status of this Radio, or, if a string value
4022 * is passed, checks a sibling Radio of the same name whose value is the value specified.
4023 * @param value {String/Boolean} Checked value, or the value of the sibling radio button to check.
4024 * @return {Ext.form.Field} this
4026 setValue : function(v){
4027 if (typeof v == 'boolean') {
4028 Ext.form.Radio.superclass.setValue.call(this, v);
4030 var r = this.getCheckEl().child('input[name=' + this.el.dom.name + '][value=' + v + ']', true);
4032 Ext.getCmp(r.id).setValue(true);
4039 getCheckEl: function(){
4041 return this.el.up('.x-form-radio-group')
4043 return this.el.up('form') || Ext.getBody();
4046 Ext.reg('radio', Ext.form.Radio);
4048 * @class Ext.form.RadioGroup
4049 * @extends Ext.form.CheckboxGroup
4050 * A grouping container for {@link Ext.form.Radio} controls.
4052 * Creates a new RadioGroup
4053 * @param {Object} config Configuration options
4056 Ext.form.RadioGroup = Ext.extend(Ext.form.CheckboxGroup, {
4058 * @cfg {Boolean} allowBlank True to allow every item in the group to be blank (defaults to true).
4059 * If allowBlank = false and no items are selected at validation time, {@link @blankText} will
4060 * be used as the error text.
4064 * @cfg {String} blankText Error text to display if the {@link #allowBlank} validation fails
4065 * (defaults to 'You must select one item in this group')
4067 blankText : 'You must select one item in this group',
4070 defaultType : 'radio',
4073 groupCls : 'x-form-radio-group',
4077 * Fires when the state of a child radio changes.
4078 * @param {Ext.form.RadioGroup} this
4079 * @param {Ext.form.Radio} checked The checked radio
4083 * Gets the selected {@link Ext.form.Radio} in the group, if it exists.
4084 * @return {Ext.form.Radio} The selected radio.
4086 getValue : function(){
4088 this.eachItem(function(item){
4098 * Sets the checked radio in the group.
4099 * @param {String/Ext.form.Radio} id The radio to check.
4100 * @param {Boolean} value The value to set the radio.
4101 * @return {Ext.form.RadioGroup} this
4103 setValue : function(id, value){
4105 if(arguments.length > 1){
4106 var f = this.getBox(id);
4110 this.eachItem(function(item){
4112 item.setValue(false);
4118 this.setValueForItem(id);
4121 this.values = arguments;
4127 fireChecked : function(){
4128 if(!this.checkTask){
4129 this.checkTask = new Ext.util.DelayedTask(this.bufferChecked, this);
4131 this.checkTask.delay(10);
4135 bufferChecked : function(){
4137 this.eachItem(function(item){
4143 this.fireEvent('change', this, out);
4146 onDestroy : function(){
4148 this.checkTask.cancel();
4149 this.checkTask = null;
4151 Ext.form.RadioGroup.superclass.onDestroy.call(this);
4156 Ext.reg('radiogroup', Ext.form.RadioGroup);
4158 * @class Ext.form.Hidden
\r
4159 * @extends Ext.form.Field
\r
4160 * A basic hidden field for storing hidden values in forms that need to be passed in the form submit.
\r
4162 * Create a new Hidden field.
\r
4163 * @param {Object} config Configuration options
\r
4166 Ext.form.Hidden = Ext.extend(Ext.form.Field, {
\r
4168 inputType : 'hidden',
\r
4171 onRender : function(){
\r
4172 Ext.form.Hidden.superclass.onRender.apply(this, arguments);
\r
4176 initEvents : function(){
\r
4177 this.originalValue = this.getValue();
\r
4180 // These are all private overrides
\r
4181 setSize : Ext.emptyFn,
\r
4182 setWidth : Ext.emptyFn,
\r
4183 setHeight : Ext.emptyFn,
\r
4184 setPosition : Ext.emptyFn,
\r
4185 setPagePosition : Ext.emptyFn,
\r
4186 markInvalid : Ext.emptyFn,
\r
4187 clearInvalid : Ext.emptyFn
\r
4189 Ext.reg('hidden', Ext.form.Hidden);/**
4190 * @class Ext.form.BasicForm
4191 * @extends Ext.util.Observable
4192 * <p>Encapsulates the DOM <form> element at the heart of the {@link Ext.form.FormPanel FormPanel} class, and provides
4193 * input field management, validation, submission, and form loading services.</p>
4194 * <p>By default, Ext Forms are submitted through Ajax, using an instance of {@link Ext.form.Action.Submit}.
4195 * To enable normal browser submission of an Ext Form, use the {@link #standardSubmit} config option.</p>
4196 * <p><b><u>File Uploads</u></b></p>
4197 * <p>{@link #fileUpload File uploads} are not performed using Ajax submission, that
4198 * is they are <b>not</b> performed using XMLHttpRequests. Instead the form is submitted in the standard
4199 * manner with the DOM <tt><form></tt> element temporarily modified to have its
4200 * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
4201 * to a dynamically generated, hidden <tt><iframe></tt> which is inserted into the document
4202 * but removed after the return data has been gathered.</p>
4203 * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
4204 * server is using JSON to send the return object, then the
4205 * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
4206 * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
4207 * <p>Characters which are significant to an HTML parser must be sent as HTML entities, so encode
4208 * "<" as "&lt;", "&" as "&amp;" etc.</p>
4209 * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
4210 * is created containing a <tt>responseText</tt> property in order to conform to the
4211 * requirements of event handlers and callbacks.</p>
4212 * <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>
4213 * and some server technologies (notably JEE) may require some custom processing in order to
4214 * retrieve parameter names and parameter values from the packet content.</p>
4216 * @param {Mixed} el The form element or its id
4217 * @param {Object} config Configuration options
4219 Ext.form.BasicForm = function(el, config){
4220 Ext.apply(this, config);
4221 if(Ext.isString(this.paramOrder)){
4222 this.paramOrder = this.paramOrder.split(/[\s,|]/);
4226 * A {@link Ext.util.MixedCollection MixedCollection) containing all the Ext.form.Fields in this form.
4227 * @type MixedCollection
4229 this.items = new Ext.util.MixedCollection(false, function(o){
4230 return o.itemId || o.id || (o.id = Ext.id());
4234 * @event beforeaction
4235 * Fires before any action is performed. Return false to cancel the action.
4236 * @param {Form} this
4237 * @param {Action} action The {@link Ext.form.Action} to be performed
4241 * @event actionfailed
4242 * Fires when an action fails.
4243 * @param {Form} this
4244 * @param {Action} action The {@link Ext.form.Action} that failed
4248 * @event actioncomplete
4249 * Fires when an action is completed.
4250 * @param {Form} this
4251 * @param {Action} action The {@link Ext.form.Action} that completed
4259 Ext.form.BasicForm.superclass.constructor.call(this);
4262 Ext.extend(Ext.form.BasicForm, Ext.util.Observable, {
4264 * @cfg {String} method
4265 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
4268 * @cfg {DataReader} reader
4269 * An Ext.data.DataReader (e.g. {@link Ext.data.XmlReader}) to be used to read
4270 * data when executing 'load' actions. This is optional as there is built-in
4271 * support for processing JSON. For additional information on using an XMLReader
4272 * see the example provided in examples/form/xml-form.html.
4275 * @cfg {DataReader} errorReader
4276 * <p>An Ext.data.DataReader (e.g. {@link Ext.data.XmlReader}) to be used to
4277 * read field error messages returned from 'submit' actions. This is optional
4278 * as there is built-in support for processing JSON.</p>
4279 * <p>The Records which provide messages for the invalid Fields must use the
4280 * Field name (or id) as the Record ID, and must contain a field called 'msg'
4281 * which contains the error message.</p>
4282 * <p>The errorReader does not have to be a full-blown implementation of a
4283 * DataReader. It simply needs to implement a <tt>read(xhr)</tt> function
4284 * which returns an Array of Records in an object with the following
4285 * structure:</p><pre><code>
4287 records: recordArray
4293 * The URL to use for form actions if one isn't supplied in the
4294 * <code>{@link #doAction doAction} options</code>.
4297 * @cfg {Boolean} fileUpload
4298 * Set to true if this form is a file upload.
4299 * <p>File uploads are not performed using normal 'Ajax' techniques, that is they are <b>not</b>
4300 * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
4301 * DOM <tt><form></tt> element temporarily modified to have its
4302 * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
4303 * to a dynamically generated, hidden <tt><iframe></tt> which is inserted into the document
4304 * but removed after the return data has been gathered.</p>
4305 * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
4306 * server is using JSON to send the return object, then the
4307 * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
4308 * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
4309 * <p>Characters which are significant to an HTML parser must be sent as HTML entities, so encode
4310 * "<" as "&lt;", "&" as "&amp;" etc.</p>
4311 * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
4312 * is created containing a <tt>responseText</tt> property in order to conform to the
4313 * requirements of event handlers and callbacks.</p>
4314 * <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>
4315 * and some server technologies (notably JEE) may require some custom processing in order to
4316 * retrieve parameter names and parameter values from the packet content.</p>
4319 * @cfg {Object} baseParams
4320 * <p>Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.</p>
4321 * <p>Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode}.</p>
4324 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
4329 * @cfg {Object} api (Optional) If specified load and submit actions will be handled
4330 * with {@link Ext.form.Action.DirectLoad} and {@link Ext.form.Action.DirectSubmit}.
4331 * Methods which have been imported by Ext.Direct can be specified here to load and submit
4333 * Such as the following:<pre><code>
4335 load: App.ss.MyProfile.load,
4336 submit: App.ss.MyProfile.submit
4339 * <p>Load actions can use <code>{@link #paramOrder}</code> or <code>{@link #paramsAsHash}</code>
4340 * to customize how the load method is invoked.
4341 * Submit actions will always use a standard form submit. The formHandler configuration must
4342 * be set on the associated server-side method which has been imported by Ext.Direct</p>
4346 * @cfg {Array/String} paramOrder <p>A list of params to be executed server side.
4347 * Defaults to <tt>undefined</tt>. Only used for the <code>{@link #api}</code>
4348 * <code>load</code> configuration.</p>
4349 * <br><p>Specify the params in the order in which they must be executed on the
4350 * server-side as either (1) an Array of String values, or (2) a String of params
4351 * delimited by either whitespace, comma, or pipe. For example,
4352 * any of the following would be acceptable:</p><pre><code>
4353 paramOrder: ['param1','param2','param3']
4354 paramOrder: 'param1 param2 param3'
4355 paramOrder: 'param1,param2,param3'
4356 paramOrder: 'param1|param2|param'
4359 paramOrder: undefined,
4362 * @cfg {Boolean} paramsAsHash Only used for the <code>{@link #api}</code>
4363 * <code>load</code> configuration. Send parameters as a collection of named
4364 * arguments (defaults to <tt>false</tt>). Providing a
4365 * <tt>{@link #paramOrder}</tt> nullifies this configuration.
4367 paramsAsHash: false,
4371 activeAction : null,
4374 * @cfg {Boolean} trackResetOnLoad If set to <tt>true</tt>, {@link #reset}() resets to the last loaded
4375 * or {@link #setValues}() data instead of when the form was first created. Defaults to <tt>false</tt>.
4377 trackResetOnLoad : false,
4380 * @cfg {Boolean} standardSubmit If set to true, standard HTML form submits are used instead of XHR (Ajax) style
4381 * form submissions. (defaults to false)<br>
4382 * <p><b>Note:</b> When using standardSubmit, the options to {@link #submit} are ignored because Ext's
4383 * Ajax infrastracture is bypassed. To pass extra parameters (baseParams and params), you will need to
4384 * create hidden fields within the form.</p>
4385 * <p>The url config option is also bypassed, so set the action as well:</p>
4387 PANEL.getForm().getEl().dom.action = 'URL'
4389 * An example encapsulating the above:
4392 standardSubmit: true,
4396 url: 'myProcess.php',
4403 handler: function(){
4404 var O = this.ownerCt;
4405 if (O.getForm().isValid()) {
4407 O.getForm().getEl().dom.action = O.url;
4409 for (i in O.baseParams) {
4413 value: O.baseParams[i]
4418 O.getForm().submit();
4426 * By default wait messages are displayed with Ext.MessageBox.wait. You can target a specific
4427 * element by passing it or its id or mask the form itself by passing in true.
4429 * @property waitMsgTarget
4433 initEl : function(el){
4434 this.el = Ext.get(el);
4435 this.id = this.el.id || Ext.id();
4436 if(!this.standardSubmit){
4437 this.el.on('submit', this.onSubmit, this);
4439 this.el.addClass('x-form');
4443 * Get the HTML form Element
4444 * @return Ext.Element
4451 onSubmit : function(e){
4456 destroy: function() {
4457 this.items.each(function(f){
4461 this.el.removeAllListeners();
4464 this.purgeListeners();
4468 * Returns true if client-side validation on the form is successful.
4471 isValid : function(){
4473 this.items.each(function(f){
4482 * <p>Returns true if any fields in this form have changed from their original values.</p>
4483 * <p>Note that if this BasicForm was configured with {@link #trackResetOnLoad} then the
4484 * Fields' <i>original values</i> are updated when the values are loaded by {@link #setValues}
4485 * or {@link #loadRecord}.</p>
4488 isDirty : function(){
4490 this.items.each(function(f){
4500 * Performs a predefined action ({@link Ext.form.Action.Submit} or
4501 * {@link Ext.form.Action.Load}) or a custom extension of {@link Ext.form.Action}
4502 * to perform application-specific processing.
4503 * @param {String/Object} actionName The name of the predefined action type,
4504 * or instance of {@link Ext.form.Action} to perform.
4505 * @param {Object} options (optional) The options to pass to the {@link Ext.form.Action}.
4506 * All of the config options listed below are supported by both the
4507 * {@link Ext.form.Action.Submit submit} and {@link Ext.form.Action.Load load}
4508 * actions unless otherwise noted (custom actions could also accept
4509 * other config options):<ul>
4511 * <li><b>url</b> : String<div class="sub-desc">The url for the action (defaults
4512 * to the form's {@link #url}.)</div></li>
4514 * <li><b>method</b> : String<div class="sub-desc">The form method to use (defaults
4515 * to the form's method, or POST if not defined)</div></li>
4517 * <li><b>params</b> : String/Object<div class="sub-desc"><p>The params to pass
4518 * (defaults to the form's baseParams, or none if not defined)</p>
4519 * <p>Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode}.</p></div></li>
4521 * <li><b>headers</b> : Object<div class="sub-desc">Request headers to set for the action
4522 * (defaults to the form's default headers)</div></li>
4524 * <li><b>success</b> : Function<div class="sub-desc">The callback that will
4525 * be invoked after a successful response (see top of
4526 * {@link Ext.form.Action.Submit submit} and {@link Ext.form.Action.Load load}
4527 * for a description of what constitutes a successful response).
4528 * The function is passed the following parameters:<ul>
4529 * <li><tt>form</tt> : Ext.form.BasicForm<div class="sub-desc">The form that requested the action</div></li>
4530 * <li><tt>action</tt> : The {@link Ext.form.Action Action} object which performed the operation.
4531 * <div class="sub-desc">The action object contains these properties of interest:<ul>
4532 * <li><tt>{@link Ext.form.Action#response response}</tt></li>
4533 * <li><tt>{@link Ext.form.Action#result result}</tt> : interrogate for custom postprocessing</li>
4534 * <li><tt>{@link Ext.form.Action#type type}</tt></li>
4535 * </ul></div></li></ul></div></li>
4537 * <li><b>failure</b> : Function<div class="sub-desc">The callback that will be invoked after a
4538 * failed transaction attempt. The function is passed the following parameters:<ul>
4539 * <li><tt>form</tt> : The {@link Ext.form.BasicForm} that requested the action.</li>
4540 * <li><tt>action</tt> : The {@link Ext.form.Action Action} object which performed the operation.
4541 * <div class="sub-desc">The action object contains these properties of interest:<ul>
4542 * <li><tt>{@link Ext.form.Action#failureType failureType}</tt></li>
4543 * <li><tt>{@link Ext.form.Action#response response}</tt></li>
4544 * <li><tt>{@link Ext.form.Action#result result}</tt> : interrogate for custom postprocessing</li>
4545 * <li><tt>{@link Ext.form.Action#type type}</tt></li>
4546 * </ul></div></li></ul></div></li>
4548 * <li><b>scope</b> : Object<div class="sub-desc">The scope in which to call the
4549 * callback functions (The <tt>this</tt> reference for the callback functions).</div></li>
4551 * <li><b>clientValidation</b> : Boolean<div class="sub-desc">Submit Action only.
4552 * Determines whether a Form's fields are validated in a final call to
4553 * {@link Ext.form.BasicForm#isValid isValid} prior to submission. Set to <tt>false</tt>
4554 * to prevent this. If undefined, pre-submission field validation is performed.</div></li></ul>
4556 * @return {BasicForm} this
4558 doAction : function(action, options){
4559 if(Ext.isString(action)){
4560 action = new Ext.form.Action.ACTION_TYPES[action](this, options);
4562 if(this.fireEvent('beforeaction', this, action) !== false){
4563 this.beforeAction(action);
4564 action.run.defer(100, action);
4570 * Shortcut to {@link #doAction do} a {@link Ext.form.Action.Submit submit action}.
4571 * @param {Object} options The options to pass to the action (see {@link #doAction} for details).<br>
4572 * <p><b>Note:</b> this is ignored when using the {@link #standardSubmit} option.</p>
4573 * <p>The following code:</p><pre><code>
4574 myFormPanel.getForm().submit({
4575 clientValidation: true,
4576 url: 'updateConsignment.php',
4578 newStatus: 'delivered'
4580 success: function(form, action) {
4581 Ext.Msg.alert('Success', action.result.msg);
4583 failure: function(form, action) {
4584 switch (action.failureType) {
4585 case Ext.form.Action.CLIENT_INVALID:
4586 Ext.Msg.alert('Failure', 'Form fields may not be submitted with invalid values');
4588 case Ext.form.Action.CONNECT_FAILURE:
4589 Ext.Msg.alert('Failure', 'Ajax communication failed');
4591 case Ext.form.Action.SERVER_INVALID:
4592 Ext.Msg.alert('Failure', action.result.msg);
4597 * would process the following server response for a successful submission:<pre><code>
4599 "success":true, // note this is Boolean, not string
4600 "msg":"Consignment updated"
4603 * and the following server response for a failed submission:<pre><code>
4605 "success":false, // note this is Boolean, not string
4606 "msg":"You do not have permission to perform this operation"
4609 * @return {BasicForm} this
4611 submit : function(options){
4612 if(this.standardSubmit){
4613 var v = this.isValid();
4615 this.el.dom.submit();
4619 var submitAction = String.format('{0}submit', this.api ? 'direct' : '');
4620 this.doAction(submitAction, options);
4625 * Shortcut to {@link #doAction do} a {@link Ext.form.Action.Load load action}.
4626 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
4627 * @return {BasicForm} this
4629 load : function(options){
4630 var loadAction = String.format('{0}load', this.api ? 'direct' : '');
4631 this.doAction(loadAction, options);
4636 * Persists the values in this form into the passed {@link Ext.data.Record} object in a beginEdit/endEdit block.
4637 * @param {Record} record The record to edit
4638 * @return {BasicForm} this
4640 updateRecord : function(record){
4642 var fs = record.fields;
4643 fs.each(function(f){
4644 var field = this.findField(f.name);
4646 record.set(f.name, field.getValue());
4654 * Loads an {@link Ext.data.Record} into this form by calling {@link #setValues} with the
4655 * {@link Ext.data.Record#data record data}.
4656 * See also {@link #trackResetOnLoad}.
4657 * @param {Record} record The record to load
4658 * @return {BasicForm} this
4660 loadRecord : function(record){
4661 this.setValues(record.data);
4666 beforeAction : function(action){
4667 var o = action.options;
4669 if(this.waitMsgTarget === true){
4670 this.el.mask(o.waitMsg, 'x-mask-loading');
4671 }else if(this.waitMsgTarget){
4672 this.waitMsgTarget = Ext.get(this.waitMsgTarget);
4673 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
4675 Ext.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
4681 afterAction : function(action, success){
4682 this.activeAction = null;
4683 var o = action.options;
4685 if(this.waitMsgTarget === true){
4687 }else if(this.waitMsgTarget){
4688 this.waitMsgTarget.unmask();
4690 Ext.MessageBox.updateProgress(1);
4691 Ext.MessageBox.hide();
4698 Ext.callback(o.success, o.scope, [this, action]);
4699 this.fireEvent('actioncomplete', this, action);
4701 Ext.callback(o.failure, o.scope, [this, action]);
4702 this.fireEvent('actionfailed', this, action);
4707 * Find a {@link Ext.form.Field} in this form.
4708 * @param {String} id The value to search for (specify either a {@link Ext.Component#id id},
4709 * {@link Ext.grid.Column#dataIndex dataIndex}, {@link Ext.form.Field#getName name or hiddenName}).
4712 findField : function(id){
4713 var field = this.items.get(id);
4714 if(!Ext.isObject(field)){
4715 this.items.each(function(f){
4716 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
4722 return field || null;
4727 * Mark fields in this form invalid in bulk.
4728 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
4729 * @return {BasicForm} this
4731 markInvalid : function(errors){
4732 if(Ext.isArray(errors)){
4733 for(var i = 0, len = errors.length; i < len; i++){
4734 var fieldError = errors[i];
4735 var f = this.findField(fieldError.id);
4737 f.markInvalid(fieldError.msg);
4743 if(!Ext.isFunction(errors[id]) && (field = this.findField(id))){
4744 field.markInvalid(errors[id]);
4752 * Set values for fields in this form in bulk.
4753 * @param {Array/Object} values Either an array in the form:<pre><code>
4754 [{id:'clientName', value:'Fred. Olsen Lines'},
4755 {id:'portOfLoading', value:'FXT'},
4756 {id:'portOfDischarge', value:'OSL'} ]</code></pre>
4757 * or an object hash of the form:<pre><code>
4759 clientName: 'Fred. Olsen Lines',
4760 portOfLoading: 'FXT',
4761 portOfDischarge: 'OSL'
4763 * @return {BasicForm} this
4765 setValues : function(values){
4766 if(Ext.isArray(values)){ // array of objects
4767 for(var i = 0, len = values.length; i < len; i++){
4769 var f = this.findField(v.id);
4771 f.setValue(v.value);
4772 if(this.trackResetOnLoad){
4773 f.originalValue = f.getValue();
4777 }else{ // object hash
4780 if(!Ext.isFunction(values[id]) && (field = this.findField(id))){
4781 field.setValue(values[id]);
4782 if(this.trackResetOnLoad){
4783 field.originalValue = field.getValue();
4792 * <p>Returns the fields in this form as an object with key/value pairs as they would be submitted using a standard form submit.
4793 * If multiple fields exist with the same name they are returned as an array.</p>
4794 * <p><b>Note:</b> The values are collected from all enabled HTML input elements within the form, <u>not</u> from
4795 * the Ext Field objects. This means that all returned values are Strings (or Arrays of Strings) and that the
4796 * value can potentially be the emptyText of a field.</p>
4797 * @param {Boolean} asString (optional) Pass true to return the values as a string. (defaults to false, returning an Object)
4798 * @return {String/Object}
4800 getValues : function(asString){
4801 var fs = Ext.lib.Ajax.serializeForm(this.el.dom);
4802 if(asString === true){
4805 return Ext.urlDecode(fs);
4808 getFieldValues : function(){
4810 this.items.each(function(f){
4811 o[f.getName()] = f.getValue();
4817 * Clears all invalid messages in this form.
4818 * @return {BasicForm} this
4820 clearInvalid : function(){
4821 this.items.each(function(f){
4829 * @return {BasicForm} this
4832 this.items.each(function(f){
4839 * Add Ext.form Components to this form's Collection. This does not result in rendering of
4840 * the passed Component, it just enables the form to validate Fields, and distribute values to
4842 * <p><b>You will not usually call this function. In order to be rendered, a Field must be added
4843 * to a {@link Ext.Container Container}, usually an {@link Ext.form.FormPanel FormPanel}.
4844 * The FormPanel to which the field is added takes care of adding the Field to the BasicForm's
4845 * collection.</b></p>
4846 * @param {Field} field1
4847 * @param {Field} field2 (optional)
4848 * @param {Field} etc (optional)
4849 * @return {BasicForm} this
4852 this.items.addAll(Array.prototype.slice.call(arguments, 0));
4858 * Removes a field from the items collection (does NOT remove its markup).
4859 * @param {Field} field
4860 * @return {BasicForm} this
4862 remove : function(field){
4863 this.items.remove(field);
4868 * Iterates through the {@link Ext.form.Field Field}s which have been {@link #add add}ed to this BasicForm,
4869 * checks them for an id attribute, and calls {@link Ext.form.Field#applyToMarkup} on the existing dom element with that id.
4870 * @return {BasicForm} this
4872 render : function(){
4873 this.items.each(function(f){
4874 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
4875 f.applyToMarkup(f.id);
4882 * Calls {@link Ext#apply} for all fields in this form with the passed object.
4883 * @param {Object} values
4884 * @return {BasicForm} this
4886 applyToFields : function(o){
4887 this.items.each(function(f){
4894 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
4895 * @param {Object} values
4896 * @return {BasicForm} this
4898 applyIfToFields : function(o){
4899 this.items.each(function(f){
4905 callFieldMethod : function(fnName, args){
4907 this.items.each(function(f){
4908 if(Ext.isFunction(f[fnName])){
4909 f[fnName].apply(f, args);
4917 Ext.BasicForm = Ext.form.BasicForm;/**
4918 * @class Ext.form.FormPanel
4919 * @extends Ext.Panel
4920 * <p>Standard form container.</p>
4922 * <p><b><u>Layout</u></b></p>
4923 * <p>By default, FormPanel is configured with <tt>layout:'form'</tt> to use an {@link Ext.layout.FormLayout}
4924 * layout manager, which styles and renders fields and labels correctly. When nesting additional Containers
4925 * within a FormPanel, you should ensure that any descendant Containers which host input Fields use the
4926 * {@link Ext.layout.FormLayout} layout manager.</p>
4928 * <p><b><u>BasicForm</u></b></p>
4929 * <p>Although <b>not listed</b> as configuration options of FormPanel, the FormPanel class accepts all
4930 * of the config options required to configure its internal {@link Ext.form.BasicForm} for:
4931 * <div class="mdetail-params"><ul>
4932 * <li>{@link Ext.form.BasicForm#fileUpload file uploads}</li>
4933 * <li>functionality for {@link Ext.form.BasicForm#doAction loading, validating and submitting} the form</li>
4936 * <p><b>Note</b>: If subclassing FormPanel, any configuration options for the BasicForm must be applied to
4937 * the <tt><b>initialConfig</b></tt> property of the FormPanel. Applying {@link Ext.form.BasicForm BasicForm}
4938 * configuration settings to <b><tt>this</tt></b> will <b>not</b> affect the BasicForm's configuration.</p>
4940 * <p><b><u>Form Validation</u></b></p>
4941 * <p>For information on form validation see the following:</p>
4942 * <div class="mdetail-params"><ul>
4943 * <li>{@link Ext.form.TextField}</li>
4944 * <li>{@link Ext.form.VTypes}</li>
4945 * <li>{@link Ext.form.BasicForm#doAction BasicForm.doAction <b>clientValidation</b> notes}</li>
4946 * <li><tt>{@link Ext.form.FormPanel#monitorValid monitorValid}</tt></li>
4949 * <p><b><u>Form Submission</u></b></p>
4950 * <p>By default, Ext Forms are submitted through Ajax, using {@link Ext.form.Action}. To enable normal browser
4951 * submission of the {@link Ext.form.BasicForm BasicForm} contained in this FormPanel, see the
4952 * <tt><b>{@link Ext.form.BasicForm#standardSubmit standardSubmit}</b></tt> option.</p>
4955 * @param {Object} config Configuration options
4958 Ext.FormPanel = Ext.extend(Ext.Panel, {
4960 * @cfg {String} formId (optional) The id of the FORM tag (defaults to an auto-generated id).
4963 * @cfg {Boolean} hideLabels
4964 * <p><tt>true</tt> to hide field labels by default (sets <tt>display:none</tt>). Defaults to
4965 * <tt>false</tt>.</p>
4966 * <p>Also see {@link Ext.Component}.<tt>{@link Ext.Component#hideLabel hideLabel}</tt>.
4969 * @cfg {Number} labelPad
4970 * The default padding in pixels for field labels (defaults to <tt>5</tt>). <tt>labelPad</tt> only
4971 * applies if <tt>{@link #labelWidth}</tt> is also specified, otherwise it will be ignored.
4974 * @cfg {String} labelSeparator
4975 * See {@link Ext.Component}.<tt>{@link Ext.Component#labelSeparator labelSeparator}</tt>
4978 * @cfg {Number} labelWidth The width of labels in pixels. This property cascades to child containers
4979 * and can be overridden on any child container (e.g., a fieldset can specify a different <tt>labelWidth</tt>
4980 * for its fields) (defaults to <tt>100</tt>).
4983 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
4986 * @cfg {Array} buttons
4987 * An array of {@link Ext.Button}s or {@link Ext.Button} configs used to add buttons to the footer of this FormPanel.<br>
4988 * <p>Buttons in the footer of a FormPanel may be configured with the option <tt>formBind: true</tt>. This causes
4989 * the form's {@link #monitorValid valid state monitor task} to enable/disable those Buttons depending on
4990 * the form's valid/invalid state.</p>
4995 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to <tt>75</tt>).
4997 minButtonWidth : 75,
5000 * @cfg {String} labelAlign The label alignment value used for the <tt>text-align</tt> specification
5001 * for the <b>container</b>. Valid values are <tt>"left</tt>", <tt>"top"</tt> or <tt>"right"</tt>
5002 * (defaults to <tt>"left"</tt>). This property cascades to child <b>containers</b> and can be
5003 * overridden on any child <b>container</b> (e.g., a fieldset can specify a different <tt>labelAlign</tt>
5006 labelAlign : 'left',
5009 * @cfg {Boolean} monitorValid If <tt>true</tt>, the form monitors its valid state <b>client-side</b> and
5010 * regularly fires the {@link #clientvalidation} event passing that state.<br>
5011 * <p>When monitoring valid state, the FormPanel enables/disables any of its configured
5012 * {@link #buttons} which have been configured with <code>formBind: true</code> depending
5013 * on whether the {@link Ext.form.BasicForm#isValid form is valid} or not. Defaults to <tt>false</tt></p>
5015 monitorValid : false,
5018 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
5023 * @cfg {String} layout Defaults to <tt>'form'</tt>. Normally this configuration property should not be altered.
5024 * For additional details see {@link Ext.layout.FormLayout} and {@link Ext.Container#layout Ext.Container.layout}.
5029 initComponent : function(){
5030 this.form = this.createForm();
5031 Ext.FormPanel.superclass.initComponent.call(this);
5035 cls: this.baseCls + '-body',
5036 method : this.method || 'POST',
5037 id : this.formId || Ext.id()
5039 if(this.fileUpload) {
5040 this.bodyCfg.enctype = 'multipart/form-data';
5046 * @event clientvalidation
5047 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5048 * @param {Ext.form.FormPanel} this
5049 * @param {Boolean} valid true if the form has passed client-side validation
5054 this.relayEvents(this.form, ['beforeaction', 'actionfailed', 'actioncomplete']);
5058 createForm : function(){
5059 var config = Ext.applyIf({listeners: {}}, this.initialConfig);
5060 return new Ext.form.BasicForm(null, config);
5064 initFields : function(){
5066 var formPanel = this;
5067 var fn = function(c){
5068 if(formPanel.isField(c)){
5072 labelAlign: c.ownerCt.labelAlign,
5073 labelWidth: c.ownerCt.labelWidth,
5074 itemCls: c.ownerCt.itemCls
5077 }else if(c.doLayout && c != formPanel){
5079 labelAlign: c.ownerCt.labelAlign,
5080 labelWidth: c.ownerCt.labelWidth,
5081 itemCls: c.ownerCt.itemCls
5083 //each check required for check/radio groups.
5084 if(c.items && c.items.each){
5085 c.items.each(fn, this);
5089 this.items.each(fn, this);
5093 getLayoutTarget : function(){
5094 return this.form.el;
5098 * Provides access to the {@link Ext.form.BasicForm Form} which this Panel contains.
5099 * @return {Ext.form.BasicForm} The {@link Ext.form.BasicForm Form} which this Panel contains.
5101 getForm : function(){
5106 onRender : function(ct, position){
5108 Ext.FormPanel.superclass.onRender.call(this, ct, position);
5109 this.form.initEl(this.body);
5113 beforeDestroy : function(){
5114 this.stopMonitoring();
5115 Ext.FormPanel.superclass.beforeDestroy.call(this);
5117 * Clear the items here to prevent them being destroyed again.
5118 * Don't move this behaviour to BasicForm because it can be used
5121 this.form.items.clear();
5122 Ext.destroy(this.form);
5125 // Determine if a Component is usable as a form Field.
5126 isField : function(c) {
5127 return !!c.setValue && !!c.getValue && !!c.markInvalid && !!c.clearInvalid;
5131 initEvents : function(){
5132 Ext.FormPanel.superclass.initEvents.call(this);
5133 this.on('remove', this.onRemove, this);
5134 this.on('add', this.onAdd, this);
5135 if(this.monitorValid){ // initialize after render
5136 this.startMonitoring();
5141 onAdd : function(ct, c) {
5142 // If a single form Field, add it
5143 if (this.isField(c)) {
5145 // If a Container, add any Fields it might contain
5146 } else if (c.findBy) {
5148 labelAlign: c.ownerCt.labelAlign,
5149 labelWidth: c.ownerCt.labelWidth,
5150 itemCls: c.ownerCt.itemCls
5152 this.form.add.apply(this.form, c.findBy(this.isField));
5157 onRemove : function(ct, c) {
5158 // If a single form Field, remove it
5159 if (this.isField(c)) {
5160 Ext.destroy(c.container.up('.x-form-item'));
5161 this.form.remove(c);
5162 // If a Container, remove any Fields it might contain
5163 } else if (c.findByType) {
5164 Ext.each(c.findBy(this.isField), this.form.remove, this.form);
5169 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
5170 * option "monitorValid"
5172 startMonitoring : function(){
5173 if(!this.validTask){
5174 this.validTask = new Ext.util.TaskRunner();
5175 this.validTask.start({
5176 run : this.bindHandler,
5177 interval : this.monitorPoll || 200,
5184 * Stops monitoring of the valid state of this form
5186 stopMonitoring : function(){
5188 this.validTask.stopAll();
5189 this.validTask = null;
5194 * This is a proxy for the underlying BasicForm's {@link Ext.form.BasicForm#load} call.
5195 * @param {Object} options The options to pass to the action (see {@link Ext.form.BasicForm#doAction} for details)
5198 this.form.load.apply(this.form, arguments);
5202 onDisable : function(){
5203 Ext.FormPanel.superclass.onDisable.call(this);
5205 this.form.items.each(function(){
5212 onEnable : function(){
5213 Ext.FormPanel.superclass.onEnable.call(this);
5215 this.form.items.each(function(){
5222 bindHandler : function(){
5224 this.form.items.each(function(f){
5225 if(!f.isValid(true)){
5231 var fitems = this.fbar.items.items;
5232 for(var i = 0, len = fitems.length; i < len; i++){
5233 var btn = fitems[i];
5234 if(btn.formBind === true && btn.disabled === valid){
5235 btn.setDisabled(!valid);
5239 this.fireEvent('clientvalidation', this, valid);
5242 Ext.reg('form', Ext.FormPanel);
5244 Ext.form.FormPanel = Ext.FormPanel;
5247 * @class Ext.form.FieldSet
\r
5248 * @extends Ext.Panel
\r
5249 * Standard container used for grouping items within a {@link Ext.form.FormPanel form}.
\r
5251 var form = new Ext.FormPanel({
\r
5252 title: 'Simple Form with FieldSets',
\r
5253 labelWidth: 75, // label settings here cascade unless overridden
\r
5254 url: 'save-form.php',
\r
5256 bodyStyle:'padding:5px 5px 0',
\r
5258 renderTo: document.body,
\r
5259 layout:'column', // arrange items in columns
\r
5260 defaults: { // defaults applied to items
\r
5263 bodyStyle: 'padding:4px'
\r
5266 // Fieldset in Column 1
\r
5269 title: 'Fieldset 1',
\r
5270 collapsible: true,
\r
5273 anchor: '-20' // leave room for error icon
\r
5275 defaultType: 'textfield',
\r
5277 fieldLabel: 'Field 1'
\r
5279 fieldLabel: 'Field 2'
\r
5281 fieldLabel: 'Field 3'
\r
5285 // Fieldset in Column 2 - Panel inside
\r
5287 title: 'Show Panel', // title, header, or checkboxToggle creates fieldset header
\r
5290 checkboxToggle: true,
\r
5291 collapsed: true, // fieldset initially collapsed
\r
5296 title: 'Panel inside a fieldset',
\r
5304 * @param {Object} config Configuration options
\r
5307 Ext.form.FieldSet = Ext.extend(Ext.Panel, {
\r
5309 * @cfg {Mixed} checkboxToggle <tt>true</tt> to render a checkbox into the fieldset frame just
\r
5310 * in front of the legend to expand/collapse the fieldset when the checkbox is toggled. (defaults
\r
5311 * to <tt>false</tt>).
\r
5312 * <p>A {@link Ext.DomHelper DomHelper} element spec may also be specified to create the checkbox.
\r
5313 * If <tt>true</tt> is specified, the default DomHelper config object used to create the element
\r
5314 * is:</p><pre><code>
\r
5315 * {tag: 'input', type: 'checkbox', name: this.checkboxName || this.id+'-checkbox'}
\r
5319 * @cfg {String} checkboxName The name to assign to the fieldset's checkbox if <tt>{@link #checkboxToggle} = true</tt>
\r
5320 * (defaults to <tt>'[checkbox id]-checkbox'</tt>).
\r
5323 * @cfg {Boolean} collapsible
\r
5324 * <tt>true</tt> to make the fieldset collapsible and have the expand/collapse toggle button automatically
\r
5325 * rendered into the legend element, <tt>false</tt> to keep the fieldset statically sized with no collapse
\r
5326 * button (defaults to <tt>false</tt>). Another option is to configure <tt>{@link #checkboxToggle}</tt>.
\r
5329 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
\r
5332 * @cfg {String} itemCls A css class to apply to the <tt>x-form-item</tt> of fields (see
\r
5333 * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl} for details).
\r
5334 * This property cascades to child containers.
\r
5337 * @cfg {String} baseCls The base CSS class applied to the fieldset (defaults to <tt>'x-fieldset'</tt>).
\r
5339 baseCls : 'x-fieldset',
\r
5341 * @cfg {String} layout The {@link Ext.Container#layout} to use inside the fieldset (defaults to <tt>'form'</tt>).
\r
5345 * @cfg {Boolean} animCollapse
\r
5346 * <tt>true</tt> to animate the transition when the panel is collapsed, <tt>false</tt> to skip the
\r
5347 * animation (defaults to <tt>false</tt>).
\r
5349 animCollapse : false,
\r
5352 onRender : function(ct, position){
\r
5354 this.el = document.createElement('fieldset');
\r
5355 this.el.id = this.id;
\r
5356 if (this.title || this.header || this.checkboxToggle) {
\r
5357 this.el.appendChild(document.createElement('legend')).className = 'x-fieldset-header';
\r
5361 Ext.form.FieldSet.superclass.onRender.call(this, ct, position);
\r
5363 if(this.checkboxToggle){
\r
5364 var o = typeof this.checkboxToggle == 'object' ?
\r
5365 this.checkboxToggle :
\r
5366 {tag: 'input', type: 'checkbox', name: this.checkboxName || this.id+'-checkbox'};
\r
5367 this.checkbox = this.header.insertFirst(o);
\r
5368 this.checkbox.dom.checked = !this.collapsed;
\r
5369 this.mon(this.checkbox, 'click', this.onCheckClick, this);
\r
5374 onCollapse : function(doAnim, animArg){
\r
5375 if(this.checkbox){
\r
5376 this.checkbox.dom.checked = false;
\r
5378 Ext.form.FieldSet.superclass.onCollapse.call(this, doAnim, animArg);
\r
5383 onExpand : function(doAnim, animArg){
\r
5384 if(this.checkbox){
\r
5385 this.checkbox.dom.checked = true;
\r
5387 Ext.form.FieldSet.superclass.onExpand.call(this, doAnim, animArg);
\r
5391 * This function is called by the fieldset's checkbox when it is toggled (only applies when
\r
5392 * checkboxToggle = true). This method should never be called externally, but can be
\r
5393 * overridden to provide custom behavior when the checkbox is toggled if needed.
\r
5395 onCheckClick : function(){
\r
5396 this[this.checkbox.dom.checked ? 'expand' : 'collapse']();
\r
5400 * @cfg {String/Number} activeItem
\r
5404 * @cfg {Mixed} applyTo
\r
5408 * @cfg {Boolean} bodyBorder
\r
5412 * @cfg {Boolean} border
\r
5416 * @cfg {Boolean/Number} bufferResize
\r
5420 * @cfg {Boolean} collapseFirst
\r
5424 * @cfg {String} defaultType
\r
5428 * @cfg {String} disabledClass
\r
5432 * @cfg {String} elements
\r
5436 * @cfg {Boolean} floating
\r
5440 * @cfg {Boolean} footer
\r
5444 * @cfg {Boolean} frame
\r
5448 * @cfg {Boolean} header
\r
5452 * @cfg {Boolean} headerAsText
\r
5456 * @cfg {Boolean} hideCollapseTool
\r
5460 * @cfg {String} iconCls
\r
5464 * @cfg {Boolean/String} shadow
\r
5468 * @cfg {Number} shadowOffset
\r
5472 * @cfg {Boolean} shim
\r
5476 * @cfg {Object/Array} tbar
\r
5480 * @cfg {String} tabTip
\r
5484 * @cfg {Boolean} titleCollapse
\r
5488 * @cfg {Array} tools
\r
5492 * @cfg {Ext.Template/Ext.XTemplate} toolTemplate
\r
5496 * @cfg {String} xtype
\r
5500 * @property header
\r
5504 * @property footer
\r
5512 * @method getBottomToolbar
\r
5516 * @method getTopToolbar
\r
5520 * @method setIconClass
\r
5528 * @event beforeclose
\r
5532 * @event bodyresize
\r
5540 * @event deactivate
\r
5544 Ext.reg('fieldset', Ext.form.FieldSet);
\r
5546 * @class Ext.form.HtmlEditor
\r
5547 * @extends Ext.form.Field
\r
5548 * Provides a lightweight HTML Editor component. Some toolbar features are not supported by Safari and will be
\r
5549 * automatically hidden when needed. These are noted in the config options where appropriate.
\r
5550 * <br><br>The editor's toolbar buttons have tooltips defined in the {@link #buttonTips} property, but they are not
\r
5551 * enabled by default unless the global {@link Ext.QuickTips} singleton is {@link Ext.QuickTips#init initialized}.
\r
5552 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
\r
5553 * supported by this editor.</b>
\r
5554 * <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
\r
5555 * any element that has display set to 'none' can cause problems in Safari and Firefox due to their default iframe reloading bugs.
\r
5556 * <br><br>Example usage:
\r
5558 // Simple example rendered with default options:
\r
5559 Ext.QuickTips.init(); // enable tooltips
\r
5560 new Ext.form.HtmlEditor({
\r
5561 renderTo: Ext.getBody(),
\r
5566 // Passed via xtype into a container and with custom options:
\r
5567 Ext.QuickTips.init(); // enable tooltips
\r
5569 title: 'HTML Editor',
\r
5570 renderTo: Ext.getBody(),
\r
5576 xtype: 'htmleditor',
\r
5577 enableColors: false,
\r
5578 enableAlignments: false
\r
5583 * Create a new HtmlEditor
\r
5584 * @param {Object} config
\r
5585 * @xtype htmleditor
\r
5588 Ext.form.HtmlEditor = Ext.extend(Ext.form.Field, {
\r
5590 * @cfg {Boolean} enableFormat Enable the bold, italic and underline buttons (defaults to true)
\r
5592 enableFormat : true,
\r
5594 * @cfg {Boolean} enableFontSize Enable the increase/decrease font size buttons (defaults to true)
\r
5596 enableFontSize : true,
\r
5598 * @cfg {Boolean} enableColors Enable the fore/highlight color buttons (defaults to true)
\r
5600 enableColors : true,
\r
5602 * @cfg {Boolean} enableAlignments Enable the left, center, right alignment buttons (defaults to true)
\r
5604 enableAlignments : true,
\r
5606 * @cfg {Boolean} enableLists Enable the bullet and numbered list buttons. Not available in Safari. (defaults to true)
\r
5608 enableLists : true,
\r
5610 * @cfg {Boolean} enableSourceEdit Enable the switch to source edit button. Not available in Safari. (defaults to true)
\r
5612 enableSourceEdit : true,
\r
5614 * @cfg {Boolean} enableLinks Enable the create link button. Not available in Safari. (defaults to true)
\r
5616 enableLinks : true,
\r
5618 * @cfg {Boolean} enableFont Enable font selection. Not available in Safari. (defaults to true)
\r
5620 enableFont : true,
\r
5622 * @cfg {String} createLinkText The default text for the create link prompt
\r
5624 createLinkText : 'Please enter the URL for the link:',
\r
5626 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
\r
5628 defaultLinkValue : 'http:/'+'/',
\r
5630 * @cfg {Array} fontFamilies An array of available font families
\r
5636 'Times New Roman',
\r
5639 defaultFont: 'tahoma',
\r
5641 * @cfg {String} defaultValue A default value to be put into the editor to resolve focus issues (defaults to ​ (Zero-width space), (Non-breaking space) in Opera and IE6).
\r
5643 defaultValue: (Ext.isOpera || Ext.isIE6) ? ' ' : '​',
\r
5645 // private properties
\r
5646 actionMode: 'wrap',
\r
5647 validationEvent : false,
\r
5648 deferHeight: true,
\r
5649 initialized : false,
\r
5650 activated : false,
\r
5651 sourceEditMode : false,
\r
5652 onFocus : Ext.emptyFn,
\r
5654 hideMode:'offsets',
\r
5655 defaultAutoCreate : {
\r
5657 style:"width:500px;height:300px;",
\r
5658 autocomplete: "off"
\r
5662 initComponent : function(){
\r
5665 * @event initialize
\r
5666 * Fires when the editor is fully initialized (including the iframe)
\r
5667 * @param {HtmlEditor} this
\r
5672 * Fires when the editor is first receives the focus. Any insertion must wait
\r
5673 * until after this event.
\r
5674 * @param {HtmlEditor} this
\r
5678 * @event beforesync
\r
5679 * Fires before the textarea is updated with content from the editor iframe. Return false
\r
5680 * to cancel the sync.
\r
5681 * @param {HtmlEditor} this
\r
5682 * @param {String} html
\r
5686 * @event beforepush
\r
5687 * Fires before the iframe editor is updated with content from the textarea. Return false
\r
5688 * to cancel the push.
\r
5689 * @param {HtmlEditor} this
\r
5690 * @param {String} html
\r
5695 * Fires when the textarea is updated with content from the editor iframe.
\r
5696 * @param {HtmlEditor} this
\r
5697 * @param {String} html
\r
5702 * Fires when the iframe editor is updated with content from the textarea.
\r
5703 * @param {HtmlEditor} this
\r
5704 * @param {String} html
\r
5708 * @event editmodechange
\r
5709 * Fires when the editor switches edit modes
\r
5710 * @param {HtmlEditor} this
\r
5711 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
\r
5718 createFontOptions : function(){
\r
5719 var buf = [], fs = this.fontFamilies, ff, lc;
\r
5720 for(var i = 0, len = fs.length; i< len; i++){
\r
5722 lc = ff.toLowerCase();
\r
5724 '<option value="',lc,'" style="font-family:',ff,';"',
\r
5725 (this.defaultFont == lc ? ' selected="true">' : '>'),
\r
5730 return buf.join('');
\r
5734 * Protected method that will not generally be called directly. It
\r
5735 * is called when the editor creates its toolbar. Override this method if you need to
\r
5736 * add custom toolbar buttons.
\r
5737 * @param {HtmlEditor} editor
\r
5739 createToolbar : function(editor){
\r
5741 var tipsEnabled = Ext.QuickTips && Ext.QuickTips.isEnabled();
\r
5743 function btn(id, toggle, handler){
\r
5746 cls : 'x-btn-icon',
\r
5747 iconCls: 'x-edit-'+id,
\r
5748 enableToggle:toggle !== false,
\r
5750 handler:handler||editor.relayBtnCmd,
\r
5751 clickEvent:'mousedown',
\r
5752 tooltip: tipsEnabled ? editor.buttonTips[id] || undefined : undefined,
\r
5753 overflowText: editor.buttonTips[id].title || undefined,
\r
5758 // build the toolbar
\r
5759 var tb = new Ext.Toolbar({
\r
5760 renderTo:this.wrap.dom.firstChild
\r
5763 // stop form submits
\r
5764 this.mon(tb.el, 'click', function(e){
\r
5765 e.preventDefault();
\r
5768 if(this.enableFont && !Ext.isSafari2){
\r
5769 this.fontSelect = tb.el.createChild({
\r
5771 cls:'x-font-select',
\r
5772 html: this.createFontOptions()
\r
5774 this.mon(this.fontSelect, 'change', function(){
\r
5775 var font = this.fontSelect.dom.value;
\r
5776 this.relayCmd('fontname', font);
\r
5777 this.deferFocus();
\r
5781 this.fontSelect.dom,
\r
5786 if(this.enableFormat){
\r
5794 if(this.enableFontSize){
\r
5797 btn('increasefontsize', false, this.adjustFont),
\r
5798 btn('decreasefontsize', false, this.adjustFont)
\r
5802 if(this.enableColors){
\r
5805 itemId:'forecolor',
\r
5807 iconCls: 'x-edit-forecolor',
\r
5808 clickEvent:'mousedown',
\r
5809 tooltip: tipsEnabled ? editor.buttonTips.forecolor || undefined : undefined,
\r
5811 menu : new Ext.menu.ColorMenu({
\r
5812 allowReselect: true,
\r
5813 focus: Ext.emptyFn,
\r
5818 select: function(cp, color){
\r
5819 this.execCmd('forecolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
\r
5820 this.deferFocus();
\r
5823 clickEvent:'mousedown'
\r
5826 itemId:'backcolor',
\r
5828 iconCls: 'x-edit-backcolor',
\r
5829 clickEvent:'mousedown',
\r
5830 tooltip: tipsEnabled ? editor.buttonTips.backcolor || undefined : undefined,
\r
5832 menu : new Ext.menu.ColorMenu({
\r
5833 focus: Ext.emptyFn,
\r
5836 allowReselect: true,
\r
5839 select: function(cp, color){
\r
5841 this.execCmd('useCSS', false);
\r
5842 this.execCmd('hilitecolor', color);
\r
5843 this.execCmd('useCSS', true);
\r
5844 this.deferFocus();
\r
5846 this.execCmd(Ext.isOpera ? 'hilitecolor' : 'backcolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
\r
5847 this.deferFocus();
\r
5851 clickEvent:'mousedown'
\r
5857 if(this.enableAlignments){
\r
5860 btn('justifyleft'),
\r
5861 btn('justifycenter'),
\r
5862 btn('justifyright')
\r
5866 if(!Ext.isSafari2){
\r
5867 if(this.enableLinks){
\r
5870 btn('createlink', false, this.createLink)
\r
5874 if(this.enableLists){
\r
5877 btn('insertorderedlist'),
\r
5878 btn('insertunorderedlist')
\r
5881 if(this.enableSourceEdit){
\r
5884 btn('sourceedit', true, function(btn){
\r
5885 this.toggleSourceEdit(!this.sourceEditMode);
\r
5895 * Protected method that will not generally be called directly. It
\r
5896 * is called when the editor initializes the iframe with HTML contents. Override this method if you
\r
5897 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
\r
5899 getDocMarkup : function(){
\r
5900 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
\r
5904 getEditorBody : function(){
\r
5905 return this.doc.body || this.doc.documentElement;
\r
5909 getDoc : function(){
\r
5910 return Ext.isIE ? this.getWin().document : (this.iframe.contentDocument || this.getWin().document);
\r
5914 getWin : function(){
\r
5915 return Ext.isIE ? this.iframe.contentWindow : window.frames[this.iframe.name];
\r
5919 onRender : function(ct, position){
\r
5920 Ext.form.HtmlEditor.superclass.onRender.call(this, ct, position);
\r
5921 this.el.dom.style.border = '0 none';
\r
5922 this.el.dom.setAttribute('tabIndex', -1);
\r
5923 this.el.addClass('x-hidden');
\r
5924 if(Ext.isIE){ // fix IE 1px bogus margin
\r
5925 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
\r
5927 this.wrap = this.el.wrap({
\r
5928 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
\r
5931 this.createToolbar(this);
\r
5933 this.disableItems(true);
\r
5934 // is this needed?
\r
5935 // this.tb.doLayout();
\r
5937 this.createIFrame();
\r
5940 var sz = this.el.getSize();
\r
5941 this.setSize(sz.width, this.height || sz.height);
\r
5945 createIFrame: function(){
\r
5946 var iframe = document.createElement('iframe');
\r
5947 iframe.name = Ext.id();
\r
5948 iframe.frameBorder = '0';
\r
5949 iframe.src = Ext.isIE ? Ext.SSL_SECURE_URL : "javascript:;";
\r
5950 this.wrap.dom.appendChild(iframe);
\r
5952 this.iframe = iframe;
\r
5954 this.monitorTask = Ext.TaskMgr.start({
\r
5955 run: this.checkDesignMode,
\r
5961 initFrame : function(){
\r
5962 Ext.TaskMgr.stop(this.monitorTask);
\r
5963 this.doc = this.getDoc();
\r
5964 this.win = this.getWin();
\r
5967 this.doc.write(this.getDocMarkup());
\r
5970 var task = { // must defer to wait for browser to be ready
\r
5972 if(this.doc.body || this.doc.readyState == 'complete'){
\r
5973 Ext.TaskMgr.stop(task);
\r
5974 this.doc.designMode="on";
\r
5975 this.initEditor.defer(10, this);
\r
5982 Ext.TaskMgr.start(task);
\r
5986 checkDesignMode : function(){
\r
5987 if(this.wrap && this.wrap.dom.offsetWidth){
\r
5988 var doc = this.getDoc();
\r
5992 if(!doc.editorInitialized || String(doc.designMode).toLowerCase() != 'on'){
\r
5998 disableItems: function(disabled){
\r
5999 if(this.fontSelect){
\r
6000 this.fontSelect.dom.disabled = disabled;
\r
6002 this.tb.items.each(function(item){
\r
6003 if(item.itemId != 'sourceedit'){
\r
6004 item.setDisabled(disabled);
\r
6010 onResize : function(w, h){
\r
6011 Ext.form.HtmlEditor.superclass.onResize.apply(this, arguments);
\r
6012 if(this.el && this.iframe){
\r
6013 if(typeof w == 'number'){
\r
6014 var aw = w - this.wrap.getFrameWidth('lr');
\r
6015 this.el.setWidth(this.adjustWidth('textarea', aw));
\r
6016 this.tb.setWidth(aw);
\r
6017 this.iframe.style.width = Math.max(aw, 0) + 'px';
\r
6019 if(typeof h == 'number'){
\r
6020 var ah = h - this.wrap.getFrameWidth('tb') - this.tb.el.getHeight();
\r
6021 this.el.setHeight(this.adjustWidth('textarea', ah));
\r
6022 this.iframe.style.height = Math.max(ah, 0) + 'px';
\r
6024 this.getEditorBody().style.height = Math.max((ah - (this.iframePad*2)), 0) + 'px';
\r
6031 * Toggles the editor between standard and source edit mode.
\r
6032 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
\r
6034 toggleSourceEdit : function(sourceEditMode){
\r
6035 if(sourceEditMode === undefined){
\r
6036 sourceEditMode = !this.sourceEditMode;
\r
6038 this.sourceEditMode = sourceEditMode === true;
\r
6039 var btn = this.tb.items.get('sourceedit');
\r
6040 if(btn.pressed !== this.sourceEditMode){
\r
6041 btn.toggle(this.sourceEditMode);
\r
6042 if(!btn.xtbHidden){
\r
6046 if(this.sourceEditMode){
\r
6047 this.disableItems(true);
\r
6049 this.iframe.className = 'x-hidden';
\r
6050 this.el.removeClass('x-hidden');
\r
6051 this.el.dom.removeAttribute('tabIndex');
\r
6054 if(this.initialized){
\r
6055 this.disableItems(false);
\r
6058 this.iframe.className = '';
\r
6059 this.el.addClass('x-hidden');
\r
6060 this.el.dom.setAttribute('tabIndex', -1);
\r
6061 this.deferFocus();
\r
6063 var lastSize = this.lastSize;
\r
6065 delete this.lastSize;
\r
6066 this.setSize(lastSize);
\r
6068 this.fireEvent('editmodechange', this, this.sourceEditMode);
\r
6071 // private used internally
\r
6072 createLink : function(){
\r
6073 var url = prompt(this.createLinkText, this.defaultLinkValue);
\r
6074 if(url && url != 'http:/'+'/'){
\r
6075 this.relayCmd('createlink', url);
\r
6079 // private (for BoxComponent)
\r
6080 adjustSize : Ext.BoxComponent.prototype.adjustSize,
\r
6082 // private (for BoxComponent)
\r
6083 getResizeEl : function(){
\r
6087 // private (for BoxComponent)
\r
6088 getPositionEl : function(){
\r
6093 initEvents : function(){
\r
6094 this.originalValue = this.getValue();
\r
6098 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
\r
6101 markInvalid : Ext.emptyFn,
\r
6104 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
\r
6107 clearInvalid : Ext.emptyFn,
\r
6109 // docs inherit from Field
\r
6110 setValue : function(v){
\r
6111 Ext.form.HtmlEditor.superclass.setValue.call(this, v);
\r
6117 * Protected method that will not generally be called directly. If you need/want
\r
6118 * custom HTML cleanup, this is the method you should override.
\r
6119 * @param {String} html The HTML to be cleaned
\r
6120 * @return {String} The cleaned HTML
\r
6122 cleanHtml : function(html){
\r
6123 html = String(html);
\r
6124 if(html.length > 5){
\r
6125 if(Ext.isWebKit){ // strip safari nonsense
\r
6126 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
\r
6129 if(html == this.defaultValue){
\r
6136 * Protected method that will not generally be called directly. Syncs the contents
\r
6137 * of the editor iframe with the textarea.
\r
6139 syncValue : function(){
\r
6140 if(this.initialized){
\r
6141 var bd = this.getEditorBody();
\r
6142 var html = bd.innerHTML;
\r
6144 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
\r
6145 var m = bs.match(/text-align:(.*?);/i);
\r
6147 html = '<div style="'+m[0]+'">' + html + '</div>';
\r
6150 html = this.cleanHtml(html);
\r
6151 if(this.fireEvent('beforesync', this, html) !== false){
\r
6152 this.el.dom.value = html;
\r
6153 this.fireEvent('sync', this, html);
\r
6158 //docs inherit from Field
\r
6159 getValue : function() {
\r
6160 this[this.sourceEditMode ? 'pushValue' : 'syncValue']();
\r
6161 return Ext.form.HtmlEditor.superclass.getValue.call(this);
\r
6165 * Protected method that will not generally be called directly. Pushes the value of the textarea
\r
6166 * into the iframe editor.
\r
6168 pushValue : function(){
\r
6169 if(this.initialized){
\r
6170 var v = this.el.dom.value;
\r
6171 if(!this.activated && v.length < 1){
\r
6172 v = this.defaultValue;
\r
6174 if(this.fireEvent('beforepush', this, v) !== false){
\r
6175 this.getEditorBody().innerHTML = v;
\r
6177 // Gecko hack, see: https://bugzilla.mozilla.org/show_bug.cgi?id=232791#c8
\r
6179 mode = d.designMode.toLowerCase();
\r
6181 d.designMode = mode.toggle('on', 'off');
\r
6182 d.designMode = mode;
\r
6184 this.fireEvent('push', this, v);
\r
6190 deferFocus : function(){
\r
6191 this.focus.defer(10, this);
\r
6194 // docs inherit from Field
\r
6195 focus : function(){
\r
6196 if(this.win && !this.sourceEditMode){
\r
6204 initEditor : function(){
\r
6205 //Destroying the component during/before initEditor can cause issues.
\r
6207 var dbody = this.getEditorBody();
\r
6208 var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
\r
6209 ss['background-attachment'] = 'fixed'; // w3c
\r
6210 dbody.bgProperties = 'fixed'; // ie
\r
6212 Ext.DomHelper.applyStyles(dbody, ss);
\r
6216 Ext.EventManager.removeAll(this.doc);
\r
6220 this.doc = this.getDoc();
\r
6222 Ext.EventManager.on(this.doc, {
\r
6223 'mousedown': this.onEditorEvent,
\r
6224 'dblclick': this.onEditorEvent,
\r
6225 'click': this.onEditorEvent,
\r
6226 'keyup': this.onEditorEvent,
\r
6232 Ext.EventManager.on(this.doc, 'keypress', this.applyCommand, this);
\r
6234 if(Ext.isIE || Ext.isWebKit || Ext.isOpera){
\r
6235 Ext.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
\r
6237 this.initialized = true;
\r
6238 this.fireEvent('initialize', this);
\r
6239 this.doc.editorInitialized = true;
\r
6245 onDestroy : function(){
\r
6246 if(this.monitorTask){
\r
6247 Ext.TaskMgr.stop(this.monitorTask);
\r
6249 if(this.rendered){
\r
6250 Ext.destroy(this.tb);
\r
6252 this.wrap.dom.innerHTML = '';
\r
6253 this.wrap.remove();
\r
6257 this.el.removeAllListeners();
\r
6263 Ext.EventManager.removeAll(this.doc);
\r
6264 for (var prop in this.doc){
\r
6265 delete this.doc[prop];
\r
6269 this.purgeListeners();
\r
6273 onFirstFocus : function(){
\r
6274 this.activated = true;
\r
6275 this.disableItems(false);
\r
6276 if(Ext.isGecko){ // prevent silly gecko errors
\r
6278 var s = this.win.getSelection();
\r
6279 if(!s.focusNode || s.focusNode.nodeType != 3){
\r
6280 var r = s.getRangeAt(0);
\r
6281 r.selectNodeContents(this.getEditorBody());
\r
6283 this.deferFocus();
\r
6286 this.execCmd('useCSS', true);
\r
6287 this.execCmd('styleWithCSS', false);
\r
6290 this.fireEvent('activate', this);
\r
6294 adjustFont: function(btn){
\r
6295 var adjust = btn.itemId == 'increasefontsize' ? 1 : -1;
\r
6297 var v = parseInt(this.doc.queryCommandValue('FontSize') || 2, 10);
\r
6298 if((Ext.isSafari && !Ext.isSafari2) || Ext.isChrome || Ext.isAir){
\r
6299 // Safari 3 values
\r
6300 // 1 = 10px, 2 = 13px, 3 = 16px, 4 = 18px, 5 = 24px, 6 = 32px
\r
6303 }else if(v <= 13){
\r
6305 }else if(v <= 16){
\r
6307 }else if(v <= 18){
\r
6309 }else if(v <= 24){
\r
6314 v = v.constrain(1, 6);
\r
6316 if(Ext.isSafari){ // safari
\r
6319 v = Math.max(1, v+adjust) + (Ext.isSafari ? 'px' : 0);
\r
6321 this.execCmd('FontSize', v);
\r
6325 onEditorEvent : function(e){
\r
6326 this.updateToolbar();
\r
6331 * Protected method that will not generally be called directly. It triggers
\r
6332 * a toolbar update by reading the markup state of the current selection in the editor.
\r
6334 updateToolbar: function(){
\r
6336 if(!this.activated){
\r
6337 this.onFirstFocus();
\r
6341 var btns = this.tb.items.map, doc = this.doc;
\r
6343 if(this.enableFont && !Ext.isSafari2){
\r
6344 var name = (this.doc.queryCommandValue('FontName')||this.defaultFont).toLowerCase();
\r
6345 if(name != this.fontSelect.dom.value){
\r
6346 this.fontSelect.dom.value = name;
\r
6349 if(this.enableFormat){
\r
6350 btns.bold.toggle(doc.queryCommandState('bold'));
\r
6351 btns.italic.toggle(doc.queryCommandState('italic'));
\r
6352 btns.underline.toggle(doc.queryCommandState('underline'));
\r
6354 if(this.enableAlignments){
\r
6355 btns.justifyleft.toggle(doc.queryCommandState('justifyleft'));
\r
6356 btns.justifycenter.toggle(doc.queryCommandState('justifycenter'));
\r
6357 btns.justifyright.toggle(doc.queryCommandState('justifyright'));
\r
6359 if(!Ext.isSafari2 && this.enableLists){
\r
6360 btns.insertorderedlist.toggle(doc.queryCommandState('insertorderedlist'));
\r
6361 btns.insertunorderedlist.toggle(doc.queryCommandState('insertunorderedlist'));
\r
6364 Ext.menu.MenuMgr.hideAll();
\r
6370 relayBtnCmd : function(btn){
\r
6371 this.relayCmd(btn.itemId);
\r
6375 * Executes a Midas editor command on the editor document and performs necessary focus and
\r
6376 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
\r
6377 * @param {String} cmd The Midas command
\r
6378 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
\r
6380 relayCmd : function(cmd, value){
\r
6383 this.execCmd(cmd, value);
\r
6384 this.updateToolbar();
\r
6385 }).defer(10, this);
\r
6389 * Executes a Midas editor command directly on the editor document.
\r
6390 * For visual commands, you should use {@link #relayCmd} instead.
\r
6391 * <b>This should only be called after the editor is initialized.</b>
\r
6392 * @param {String} cmd The Midas command
\r
6393 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
\r
6395 execCmd : function(cmd, value){
\r
6396 this.doc.execCommand(cmd, false, value === undefined ? null : value);
\r
6401 applyCommand : function(e){
\r
6403 var c = e.getCharCode(), cmd;
\r
6405 c = String.fromCharCode(c);
\r
6414 cmd = 'underline';
\r
6419 this.execCmd(cmd);
\r
6420 this.deferFocus();
\r
6421 e.preventDefault();
\r
6428 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
\r
6430 * @param {String} text
\r
6432 insertAtCursor : function(text){
\r
6433 if(!this.activated){
\r
6438 var r = this.doc.selection.createRange();
\r
6441 r.pasteHTML(text);
\r
6443 this.deferFocus();
\r
6445 }else if(Ext.isGecko || Ext.isOpera){
\r
6447 this.execCmd('InsertHTML', text);
\r
6448 this.deferFocus();
\r
6449 }else if(Ext.isWebKit){
\r
6450 this.execCmd('InsertText', text);
\r
6451 this.deferFocus();
\r
6456 fixKeys : function(){ // load time branching for fastest keydown performance
\r
6458 return function(e){
\r
6459 var k = e.getKey(), r;
\r
6462 r = this.doc.selection.createRange();
\r
6465 r.pasteHTML(' ');
\r
6466 this.deferFocus();
\r
6468 }else if(k == e.ENTER){
\r
6469 r = this.doc.selection.createRange();
\r
6471 var target = r.parentElement();
\r
6472 if(!target || target.tagName.toLowerCase() != 'li'){
\r
6474 r.pasteHTML('<br />');
\r
6475 r.collapse(false);
\r
6481 }else if(Ext.isOpera){
\r
6482 return function(e){
\r
6483 var k = e.getKey();
\r
6487 this.execCmd('InsertHTML',' ');
\r
6488 this.deferFocus();
\r
6491 }else if(Ext.isWebKit){
\r
6492 return function(e){
\r
6493 var k = e.getKey();
\r
6496 this.execCmd('InsertText','\t');
\r
6497 this.deferFocus();
\r
6504 * Returns the editor's toolbar. <b>This is only available after the editor has been rendered.</b>
\r
6505 * @return {Ext.Toolbar}
\r
6507 getToolbar : function(){
\r
6512 * Object collection of toolbar tooltips for the buttons in the editor. The key
\r
6513 * is the command id associated with that button and the value is a valid QuickTips object.
\r
6518 title: 'Bold (Ctrl+B)',
\r
6519 text: 'Make the selected text bold.',
\r
6520 cls: 'x-html-editor-tip'
\r
6523 title: 'Italic (Ctrl+I)',
\r
6524 text: 'Make the selected text italic.',
\r
6525 cls: 'x-html-editor-tip'
\r
6533 title: 'Bold (Ctrl+B)',
\r
6534 text: 'Make the selected text bold.',
\r
6535 cls: 'x-html-editor-tip'
\r
6538 title: 'Italic (Ctrl+I)',
\r
6539 text: 'Make the selected text italic.',
\r
6540 cls: 'x-html-editor-tip'
\r
6543 title: 'Underline (Ctrl+U)',
\r
6544 text: 'Underline the selected text.',
\r
6545 cls: 'x-html-editor-tip'
\r
6547 increasefontsize : {
\r
6548 title: 'Grow Text',
\r
6549 text: 'Increase the font size.',
\r
6550 cls: 'x-html-editor-tip'
\r
6552 decreasefontsize : {
\r
6553 title: 'Shrink Text',
\r
6554 text: 'Decrease the font size.',
\r
6555 cls: 'x-html-editor-tip'
\r
6558 title: 'Text Highlight Color',
\r
6559 text: 'Change the background color of the selected text.',
\r
6560 cls: 'x-html-editor-tip'
\r
6563 title: 'Font Color',
\r
6564 text: 'Change the color of the selected text.',
\r
6565 cls: 'x-html-editor-tip'
\r
6568 title: 'Align Text Left',
\r
6569 text: 'Align text to the left.',
\r
6570 cls: 'x-html-editor-tip'
\r
6573 title: 'Center Text',
\r
6574 text: 'Center text in the editor.',
\r
6575 cls: 'x-html-editor-tip'
\r
6578 title: 'Align Text Right',
\r
6579 text: 'Align text to the right.',
\r
6580 cls: 'x-html-editor-tip'
\r
6582 insertunorderedlist : {
\r
6583 title: 'Bullet List',
\r
6584 text: 'Start a bulleted list.',
\r
6585 cls: 'x-html-editor-tip'
\r
6587 insertorderedlist : {
\r
6588 title: 'Numbered List',
\r
6589 text: 'Start a numbered list.',
\r
6590 cls: 'x-html-editor-tip'
\r
6593 title: 'Hyperlink',
\r
6594 text: 'Make the selected text a hyperlink.',
\r
6595 cls: 'x-html-editor-tip'
\r
6598 title: 'Source Edit',
\r
6599 text: 'Switch to source editing mode.',
\r
6600 cls: 'x-html-editor-tip'
\r
6604 // hide stuff that is not compatible
\r
6618 * @event specialkey
\r
6622 * @cfg {String} fieldClass @hide
\r
6625 * @cfg {String} focusClass @hide
\r
6628 * @cfg {String} autoCreate @hide
\r
6631 * @cfg {String} inputType @hide
\r
6634 * @cfg {String} invalidClass @hide
\r
6637 * @cfg {String} invalidText @hide
\r
6640 * @cfg {String} msgFx @hide
\r
6643 * @cfg {String} validateOnBlur @hide
\r
6646 * @cfg {Boolean} allowDomMove @hide
\r
6649 * @cfg {String} applyTo @hide
\r
6652 * @cfg {String} autoHeight @hide
\r
6655 * @cfg {String} autoWidth @hide
\r
6658 * @cfg {String} cls @hide
\r
6661 * @cfg {String} disabled @hide
\r
6664 * @cfg {String} disabledClass @hide
\r
6667 * @cfg {String} msgTarget @hide
\r
6670 * @cfg {String} readOnly @hide
\r
6673 * @cfg {String} style @hide
\r
6676 * @cfg {String} validationDelay @hide
\r
6679 * @cfg {String} validationEvent @hide
\r
6682 * @cfg {String} tabIndex @hide
\r
6685 * @property disabled
\r
6689 * @method applyToMarkup
\r
6701 * @method validate
\r
6709 * @method setDisabled
\r
6717 Ext.reg('htmleditor', Ext.form.HtmlEditor);/**
\r
6718 * @class Ext.form.TimeField
\r
6719 * @extends Ext.form.ComboBox
\r
6720 * Provides a time input field with a time dropdown and automatic time validation. Example usage:
\r
6722 new Ext.form.TimeField({
\r
6723 minValue: '9:00 AM',
\r
6724 maxValue: '6:00 PM',
\r
6729 * Create a new TimeField
\r
6730 * @param {Object} config
\r
6731 * @xtype timefield
\r
6733 Ext.form.TimeField = Ext.extend(Ext.form.ComboBox, {
\r
6735 * @cfg {Date/String} minValue
\r
6736 * The minimum allowed time. Can be either a Javascript date object with a valid time value or a string
\r
6737 * time in a valid format -- see {@link #format} and {@link #altFormats} (defaults to null).
\r
6741 * @cfg {Date/String} maxValue
\r
6742 * The maximum allowed time. Can be either a Javascript date object with a valid time value or a string
\r
6743 * time in a valid format -- see {@link #format} and {@link #altFormats} (defaults to null).
\r
6747 * @cfg {String} minText
\r
6748 * The error text to display when the date in the cell is before minValue (defaults to
\r
6749 * 'The time in this field must be equal to or after {0}').
\r
6751 minText : "The time in this field must be equal to or after {0}",
\r
6753 * @cfg {String} maxText
\r
6754 * The error text to display when the time is after maxValue (defaults to
\r
6755 * 'The time in this field must be equal to or before {0}').
\r
6757 maxText : "The time in this field must be equal to or before {0}",
\r
6759 * @cfg {String} invalidText
\r
6760 * The error text to display when the time in the field is invalid (defaults to
\r
6761 * '{value} is not a valid time').
\r
6763 invalidText : "{0} is not a valid time",
\r
6765 * @cfg {String} format
\r
6766 * The default time format string which can be overriden for localization support. The format must be
\r
6767 * valid according to {@link Date#parseDate} (defaults to 'g:i A', e.g., '3:15 PM'). For 24-hour time
\r
6768 * format try 'H:i' instead.
\r
6772 * @cfg {String} altFormats
\r
6773 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
\r
6774 * format (defaults to 'g:ia|g:iA|g:i a|g:i A|h:i|g:i|H:i|ga|ha|gA|h a|g a|g A|gi|hi|gia|hia|g|H').
\r
6776 altFormats : "g:ia|g:iA|g:i a|g:i A|h:i|g:i|H:i|ga|ha|gA|h a|g a|g A|gi|hi|gia|hia|g|H",
\r
6778 * @cfg {Number} increment
\r
6779 * The number of minutes between each time value in the list (defaults to 15).
\r
6783 // private override
\r
6785 // private override
\r
6786 triggerAction: 'all',
\r
6787 // private override
\r
6790 // private - This is the date to use when generating time values in the absence of either minValue
\r
6791 // or maxValue. Using the current date causes DST issues on DST boundary dates, so this is an
\r
6792 // arbitrary "safe" date that can be any date aside from DST boundary dates.
\r
6793 initDate: '1/1/2008',
\r
6796 initComponent : function(){
\r
6797 if(typeof this.minValue == "string"){
\r
6798 this.minValue = this.parseDate(this.minValue);
\r
6800 if(typeof this.maxValue == "string"){
\r
6801 this.maxValue = this.parseDate(this.maxValue);
\r
6805 var min = this.parseDate(this.minValue) || new Date(this.initDate).clearTime();
\r
6806 var max = this.parseDate(this.maxValue) || new Date(this.initDate).clearTime().add('mi', (24 * 60) - 1);
\r
6808 while(min <= max){
\r
6809 times.push(min.dateFormat(this.format));
\r
6810 min = min.add('mi', this.increment);
\r
6812 this.store = times;
\r
6814 Ext.form.TimeField.superclass.initComponent.call(this);
\r
6818 getValue : function(){
\r
6819 var v = Ext.form.TimeField.superclass.getValue.call(this);
\r
6820 return this.formatDate(this.parseDate(v)) || '';
\r
6824 setValue : function(value){
\r
6825 return Ext.form.TimeField.superclass.setValue.call(this, this.formatDate(this.parseDate(value)));
\r
6828 // private overrides
\r
6829 validateValue : Ext.form.DateField.prototype.validateValue,
\r
6830 parseDate : Ext.form.DateField.prototype.parseDate,
\r
6831 formatDate : Ext.form.DateField.prototype.formatDate,
\r
6834 beforeBlur : function(){
\r
6835 var v = this.parseDate(this.getRawValue());
\r
6837 this.setValue(v.dateFormat(this.format));
\r
6839 Ext.form.TimeField.superclass.beforeBlur.call(this);
\r
6843 * @cfg {Boolean} grow @hide
\r
6846 * @cfg {Number} growMin @hide
\r
6849 * @cfg {Number} growMax @hide
\r
6853 * @method autoSize
\r
6856 Ext.reg('timefield', Ext.form.TimeField);/**
6857 * @class Ext.form.Label
6858 * @extends Ext.BoxComponent
6859 * Basic Label field.
6861 * Creates a new Label
6862 * @param {Ext.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
6863 * element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
6864 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
6867 Ext.form.Label = Ext.extend(Ext.BoxComponent, {
6869 * @cfg {String} text The plain text to display within the label (defaults to ''). If you need to include HTML
6870 * tags within the label's innerHTML, use the {@link #html} config instead.
6873 * @cfg {String} forId The id of the input element to which this label will be bound via the standard HTML 'for'
6874 * attribute. If not specified, the attribute will not be added to the label.
6877 * @cfg {String} html An HTML fragment that will be used as the label's innerHTML (defaults to '').
6878 * Note that if {@link #text} is specified it will take precedence and this value will be ignored.
6882 onRender : function(ct, position){
6884 this.el = document.createElement('label');
6885 this.el.id = this.getId();
6886 this.el.innerHTML = this.text ? Ext.util.Format.htmlEncode(this.text) : (this.html || '');
6888 this.el.setAttribute('for', this.forId);
6891 Ext.form.Label.superclass.onRender.call(this, ct, position);
6895 * Updates the label's innerHTML with the specified string.
6896 * @param {String} text The new label text
6897 * @param {Boolean} encode (optional) False to skip HTML-encoding the text when rendering it
6898 * to the label (defaults to true which encodes the value). This might be useful if you want to include
6899 * tags in the label's innerHTML rather than rendering them as string literals per the default logic.
6900 * @return {Label} this
6902 setText : function(t, encode){
6903 var e = encode === false;
6904 this[!e ? 'text' : 'html'] = t;
6905 delete this[e ? 'text' : 'html'];
6907 this.el.dom.innerHTML = encode !== false ? Ext.util.Format.htmlEncode(t) : t;
6913 Ext.reg('label', Ext.form.Label);/**
6914 * @class Ext.form.Action
6915 * <p>The subclasses of this class provide actions to perform upon {@link Ext.form.BasicForm Form}s.</p>
6916 * <p>Instances of this class are only created by a {@link Ext.form.BasicForm Form} when
6917 * the Form needs to perform an action such as submit or load. The Configuration options
6918 * listed for this class are set through the Form's action methods: {@link Ext.form.BasicForm#submit submit},
6919 * {@link Ext.form.BasicForm#load load} and {@link Ext.form.BasicForm#doAction doAction}</p>
6920 * <p>The instance of Action which performed the action is passed to the success
6921 * and failure callbacks of the Form's action methods ({@link Ext.form.BasicForm#submit submit},
6922 * {@link Ext.form.BasicForm#load load} and {@link Ext.form.BasicForm#doAction doAction}),
6923 * and to the {@link Ext.form.BasicForm#actioncomplete actioncomplete} and
6924 * {@link Ext.form.BasicForm#actionfailed actionfailed} event handlers.</p>
6926 Ext.form.Action = function(form, options){
6928 this.options = options || {};
6932 * Failure type returned when client side validation of the Form fails
6933 * thus aborting a submit action. Client side validation is performed unless
6934 * {@link #clientValidation} is explicitly set to <tt>false</tt>.
6938 Ext.form.Action.CLIENT_INVALID = 'client';
6940 * <p>Failure type returned when server side processing fails and the {@link #result}'s
6941 * <tt style="font-weight:bold">success</tt> property is set to <tt>false</tt>.</p>
6942 * <p>In the case of a form submission, field-specific error messages may be returned in the
6943 * {@link #result}'s <tt style="font-weight:bold">errors</tt> property.</p>
6947 Ext.form.Action.SERVER_INVALID = 'server';
6949 * Failure type returned when a communication error happens when attempting
6950 * to send a request to the remote server. The {@link #response} may be examined to
6951 * provide further information.
6955 Ext.form.Action.CONNECT_FAILURE = 'connect';
6957 * Failure type returned when the response's <tt style="font-weight:bold">success</tt>
6958 * property is set to <tt>false</tt>, or no field values are returned in the response's
6959 * <tt style="font-weight:bold">data</tt> property.
6963 Ext.form.Action.LOAD_FAILURE = 'load';
6965 Ext.form.Action.prototype = {
6967 * @cfg {String} url The URL that the Action is to invoke.
6970 * @cfg {Boolean} reset When set to <tt><b>true</b></tt>, causes the Form to be
6971 * {@link Ext.form.BasicForm.reset reset} on Action success. If specified, this happens
6972 * <b>before</b> the {@link #success} callback is called and before the Form's
6973 * {@link Ext.form.BasicForm.actioncomplete actioncomplete} event fires.
6976 * @cfg {String} method The HTTP method to use to access the requested URL. Defaults to the
6977 * {@link Ext.form.BasicForm}'s method, or if that is not specified, the underlying DOM form's method.
6980 * @cfg {Mixed} params <p>Extra parameter values to pass. These are added to the Form's
6981 * {@link Ext.form.BasicForm#baseParams} and passed to the specified URL along with the Form's
6983 * <p>Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode}.</p>
6986 * @cfg {Number} timeout The number of seconds to wait for a server response before
6987 * failing with the {@link #failureType} as {@link #Action.CONNECT_FAILURE}. If not specified,
6988 * defaults to the configured <tt>{@link Ext.form.BasicForm#timeout timeout}</tt> of the
6989 * {@link Ext.form.BasicForm form}.
6992 * @cfg {Function} success The function to call when a valid success return packet is recieved.
6993 * The function is passed the following parameters:<ul class="mdetail-params">
6994 * <li><b>form</b> : Ext.form.BasicForm<div class="sub-desc">The form that requested the action</div></li>
6995 * <li><b>action</b> : Ext.form.Action<div class="sub-desc">The Action class. The {@link #result}
6996 * property of this object may be examined to perform custom postprocessing.</div></li>
7000 * @cfg {Function} failure The function to call when a failure packet was recieved, or when an
7001 * error ocurred in the Ajax communication.
7002 * The function is passed the following parameters:<ul class="mdetail-params">
7003 * <li><b>form</b> : Ext.form.BasicForm<div class="sub-desc">The form that requested the action</div></li>
7004 * <li><b>action</b> : Ext.form.Action<div class="sub-desc">The Action class. If an Ajax
7005 * error ocurred, the failure type will be in {@link #failureType}. The {@link #result}
7006 * property of this object may be examined to perform custom postprocessing.</div></li>
7010 * @cfg {Object} scope The scope in which to call the callback functions (The <tt>this</tt> reference
7011 * for the callback functions).
7014 * @cfg {String} waitMsg The message to be displayed by a call to {@link Ext.MessageBox#wait}
7015 * during the time the action is being processed.
7018 * @cfg {String} waitTitle The title to be displayed by a call to {@link Ext.MessageBox#wait}
7019 * during the time the action is being processed.
7023 * The type of action this Action instance performs.
7024 * Currently only "submit" and "load" are supported.
7029 * The type of failure detected will be one of these: {@link #CLIENT_INVALID},
7030 * {@link #SERVER_INVALID}, {@link #CONNECT_FAILURE}, or {@link #LOAD_FAILURE}. Usage:
7032 var fp = new Ext.form.FormPanel({
7037 handler: function(){
7038 if(fp.getForm().isValid()){
7039 fp.getForm().submit({
7040 url: 'form-submit.php',
7041 waitMsg: 'Submitting your data...',
7042 success: function(form, action){
7043 // server responded with success = true
7044 var result = action.{@link #result};
7046 failure: function(form, action){
7047 if (action.{@link #failureType} === Ext.form.Action.{@link #CONNECT_FAILURE}) {
7048 Ext.Msg.alert('Error',
7049 'Status:'+action.{@link #response}.status+': '+
7050 action.{@link #response}.statusText);
7052 if (action.failureType === Ext.form.Action.{@link #SERVER_INVALID}){
7053 // server responded with success = false
7054 Ext.Msg.alert('Invalid', action.{@link #result}.errormsg);
7062 handler: function(){
7063 fp.getForm().reset();
7067 * @property failureType
7071 * The XMLHttpRequest object used to perform the action.
7072 * @property response
7076 * The decoded response object containing a boolean <tt style="font-weight:bold">success</tt> property and
7077 * other, action-specific properties.
7083 run : function(options){
7088 success : function(response){
7093 handleResponse : function(response){
7097 // default connection failure
7098 failure : function(response){
7099 this.response = response;
7100 this.failureType = Ext.form.Action.CONNECT_FAILURE;
7101 this.form.afterAction(this, false);
7105 // shared code among all Actions to validate that there was a response
7106 // with either responseText or responseXml
7107 processResponse : function(response){
7108 this.response = response;
7109 if(!response.responseText && !response.responseXML){
7112 this.result = this.handleResponse(response);
7116 // utility functions used internally
7117 getUrl : function(appendParams){
7118 var url = this.options.url || this.form.url || this.form.el.dom.action;
7120 var p = this.getParams();
7122 url = Ext.urlAppend(url, p);
7129 getMethod : function(){
7130 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7134 getParams : function(){
7135 var bp = this.form.baseParams;
7136 var p = this.options.params;
7138 if(typeof p == "object"){
7139 p = Ext.urlEncode(Ext.applyIf(p, bp));
7140 }else if(typeof p == 'string' && bp){
7141 p += '&' + Ext.urlEncode(bp);
7144 p = Ext.urlEncode(bp);
7150 createCallback : function(opts){
7151 var opts = opts || {};
7153 success: this.success,
7154 failure: this.failure,
7156 timeout: (opts.timeout*1000) || (this.form.timeout*1000),
7157 upload: this.form.fileUpload ? this.success : undefined
7163 * @class Ext.form.Action.Submit
7164 * @extends Ext.form.Action
7165 * <p>A class which handles submission of data from {@link Ext.form.BasicForm Form}s
7166 * and processes the returned response.</p>
7167 * <p>Instances of this class are only created by a {@link Ext.form.BasicForm Form} when
7168 * {@link Ext.form.BasicForm#submit submit}ting.</p>
7169 * <p><u><b>Response Packet Criteria</b></u></p>
7170 * <p>A response packet may contain:
7171 * <div class="mdetail-params"><ul>
7172 * <li><b><code>success</code></b> property : Boolean
7173 * <div class="sub-desc">The <code>success</code> property is required.</div></li>
7174 * <li><b><code>errors</code></b> property : Object
7175 * <div class="sub-desc"><div class="sub-desc">The <code>errors</code> property,
7176 * which is optional, contains error messages for invalid fields.</div></li>
7178 * <p><u><b>JSON Packets</b></u></p>
7179 * <p>By default, response packets are assumed to be JSON, so a typical response
7180 * packet may look like this:</p><pre><code>
7184 clientCode: "Client not found",
7185 portOfLoading: "This field must not be null"
7188 * <p>Other data may be placed into the response for processing by the {@link Ext.form.BasicForm}'s callback
7189 * or event handler methods. The object decoded from this JSON is available in the
7190 * {@link Ext.form.Action#result result} property.</p>
7191 * <p>Alternatively, if an {@link #errorReader} is specified as an {@link Ext.data.XmlReader XmlReader}:</p><pre><code>
7192 errorReader: new Ext.data.XmlReader({
7200 * <p>then the results may be sent back in XML format:</p><pre><code>
7201 <?xml version="1.0" encoding="UTF-8"?>
7202 <message success="false">
7205 <id>clientCode</id>
7206 <msg><![CDATA[Code not found. <br /><i>This is a test validation message from the server </i>]]></msg>
7209 <id>portOfLoading</id>
7210 <msg><![CDATA[Port not found. <br /><i>This is a test validation message from the server </i>]]></msg>
7215 * <p>Other elements may be placed into the response XML for processing by the {@link Ext.form.BasicForm}'s callback
7216 * or event handler methods. The XML document is available in the {@link #errorReader}'s {@link Ext.data.XmlReader#xmlData xmlData} property.</p>
7218 Ext.form.Action.Submit = function(form, options){
7219 Ext.form.Action.Submit.superclass.constructor.call(this, form, options);
7222 Ext.extend(Ext.form.Action.Submit, Ext.form.Action, {
7224 * @cfg {Ext.data.DataReader} errorReader <p><b>Optional. JSON is interpreted with
7225 * no need for an errorReader.</b></p>
7226 * <p>A Reader which reads a single record from the returned data. The DataReader's
7227 * <b>success</b> property specifies how submission success is determined. The Record's
7228 * data provides the error messages to apply to any invalid form Fields.</p>
7231 * @cfg {boolean} clientValidation Determines whether a Form's fields are validated
7232 * in a final call to {@link Ext.form.BasicForm#isValid isValid} prior to submission.
7233 * Pass <tt>false</tt> in the Form's submit options to prevent this. If not defined, pre-submission field validation
7240 var o = this.options;
7241 var method = this.getMethod();
7242 var isGet = method == 'GET';
7243 if(o.clientValidation === false || this.form.isValid()){
7244 Ext.Ajax.request(Ext.apply(this.createCallback(o), {
7245 form:this.form.el.dom,
7246 url:this.getUrl(isGet),
7249 params:!isGet ? this.getParams() : null,
7250 isUpload: this.form.fileUpload
7252 }else if (o.clientValidation !== false){ // client validation failed
7253 this.failureType = Ext.form.Action.CLIENT_INVALID;
7254 this.form.afterAction(this, false);
7259 success : function(response){
7260 var result = this.processResponse(response);
7261 if(result === true || result.success){
7262 this.form.afterAction(this, true);
7266 this.form.markInvalid(result.errors);
7267 this.failureType = Ext.form.Action.SERVER_INVALID;
7269 this.form.afterAction(this, false);
7273 handleResponse : function(response){
7274 if(this.form.errorReader){
7275 var rs = this.form.errorReader.read(response);
7278 for(var i = 0, len = rs.records.length; i < len; i++) {
7279 var r = rs.records[i];
7283 if(errors.length < 1){
7287 success : rs.success,
7291 return Ext.decode(response.responseText);
7297 * @class Ext.form.Action.Load
7298 * @extends Ext.form.Action
7299 * <p>A class which handles loading of data from a server into the Fields of an {@link Ext.form.BasicForm}.</p>
7300 * <p>Instances of this class are only created by a {@link Ext.form.BasicForm Form} when
7301 * {@link Ext.form.BasicForm#load load}ing.</p>
7302 * <p><u><b>Response Packet Criteria</b></u></p>
7303 * <p>A response packet <b>must</b> contain:
7304 * <div class="mdetail-params"><ul>
7305 * <li><b><code>success</code></b> property : Boolean</li>
7306 * <li><b><code>data</code></b> property : Object</li>
7307 * <div class="sub-desc">The <code>data</code> property contains the values of Fields to load.
7308 * The individual value object for each Field is passed to the Field's
7309 * {@link Ext.form.Field#setValue setValue} method.</div></li>
7311 * <p><u><b>JSON Packets</b></u></p>
7312 * <p>By default, response packets are assumed to be JSON, so for the following form load call:<pre><code>
7313 var myFormPanel = new Ext.form.FormPanel({
7314 title: 'Client and routing info',
7316 fieldLabel: 'Client',
7319 fieldLabel: 'Port of loading',
7320 name: 'portOfLoading'
7322 fieldLabel: 'Port of discharge',
7323 name: 'portOfDischarge'
7326 myFormPanel.{@link Ext.form.FormPanel#getForm getForm}().{@link Ext.form.BasicForm#load load}({
7327 url: '/getRoutingInfo.php',
7329 consignmentRef: myConsignmentRef
7331 failure: function(form, action() {
7332 Ext.Msg.alert("Load failed", action.result.errorMessage);
7336 * a <b>success response</b> packet may look like this:</p><pre><code>
7340 clientName: "Fred. Olsen Lines",
7341 portOfLoading: "FXT",
7342 portOfDischarge: "OSL"
7345 * while a <b>failure response</b> packet may look like this:</p><pre><code>
7348 errorMessage: "Consignment reference not found"
7350 * <p>Other data may be placed into the response for processing the {@link Ext.form.BasicForm Form}'s
7351 * callback or event handler methods. The object decoded from this JSON is available in the
7352 * {@link Ext.form.Action#result result} property.</p>
7354 Ext.form.Action.Load = function(form, options){
7355 Ext.form.Action.Load.superclass.constructor.call(this, form, options);
7356 this.reader = this.form.reader;
7359 Ext.extend(Ext.form.Action.Load, Ext.form.Action, {
7365 Ext.Ajax.request(Ext.apply(
7366 this.createCallback(this.options), {
7367 method:this.getMethod(),
7368 url:this.getUrl(false),
7369 headers: this.options.headers,
7370 params:this.getParams()
7375 success : function(response){
7376 var result = this.processResponse(response);
7377 if(result === true || !result.success || !result.data){
7378 this.failureType = Ext.form.Action.LOAD_FAILURE;
7379 this.form.afterAction(this, false);
7382 this.form.clearInvalid();
7383 this.form.setValues(result.data);
7384 this.form.afterAction(this, true);
7388 handleResponse : function(response){
7389 if(this.form.reader){
7390 var rs = this.form.reader.read(response);
7391 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7393 success : rs.success,
7397 return Ext.decode(response.responseText);
7404 * @class Ext.form.Action.DirectLoad
7405 * @extends Ext.form.Action.Load
7406 * Provides Ext.direct support for loading form data. This example illustrates usage
7407 * of Ext.Direct to load a submit a form through Ext.Direct.
7409 var myFormPanel = new Ext.form.FormPanel({
7410 // configs for FormPanel
7411 title: 'Basic Information',
7416 handler: function(){
7417 basicInfo.getForm().submit({
7425 // configs apply to child items
7426 defaults: {anchor: '100%'},
7427 defaultType: 'textfield',
7429 // form fields go here
7432 // configs for BasicForm
7434 load: Profile.getBasicInfo,
7435 // The server-side must mark the submit handler as a 'formHandler'
7436 submit: Profile.updateBasicInfo
7442 myFormPanel.getForm().load({
7449 Ext.form.Action.DirectLoad = Ext.extend(Ext.form.Action.Load, {
7450 constructor: function(form, opts) {
7451 Ext.form.Action.DirectLoad.superclass.constructor.call(this, form, opts);
7456 var args = this.getParams();
7457 args.push(this.success, this);
7458 this.form.api.load.apply(window, args);
7461 getParams: function() {
7462 var buf = [], o = {};
7463 var bp = this.form.baseParams;
7464 var p = this.options.params;
7465 Ext.apply(o, p, bp);
7466 var paramOrder = this.form.paramOrder;
7468 for(var i = 0, len = paramOrder.length; i < len; i++){
7469 buf.push(o[paramOrder[i]]);
7471 }else if(this.form.paramsAsHash){
7476 // Direct actions have already been processed and therefore
7477 // we can directly set the result; Direct Actions do not have
7478 // a this.response property.
7479 processResponse: function(result) {
7480 this.result = result;
7486 * @class Ext.form.Action.DirectSubmit
7487 * @extends Ext.form.Action.Submit
7488 * Provides Ext.direct support for submitting form data.
7489 * See {@link Ext.form.Action.DirectLoad}.
7491 Ext.form.Action.DirectSubmit = Ext.extend(Ext.form.Action.Submit, {
7492 constructor: function(form, opts) {
7493 Ext.form.Action.DirectSubmit.superclass.constructor.call(this, form, opts);
7495 type: 'directsubmit',
7496 // override of Submit
7498 var o = this.options;
7499 if(o.clientValidation === false || this.form.isValid()){
7500 // tag on any additional params to be posted in the
7502 this.success.params = this.getParams();
7503 this.form.api.submit(this.form.el.dom, this.success, this);
7504 }else if (o.clientValidation !== false){ // client validation failed
7505 this.failureType = Ext.form.Action.CLIENT_INVALID;
7506 this.form.afterAction(this, false);
7510 getParams: function() {
7512 var bp = this.form.baseParams;
7513 var p = this.options.params;
7514 Ext.apply(o, p, bp);
7517 // Direct actions have already been processed and therefore
7518 // we can directly set the result; Direct Actions do not have
7519 // a this.response property.
7520 processResponse: function(result) {
7521 this.result = result;
7527 Ext.form.Action.ACTION_TYPES = {
7528 'load' : Ext.form.Action.Load,
7529 'submit' : Ext.form.Action.Submit,
7530 'directload': Ext.form.Action.DirectLoad,
7531 'directsubmit': Ext.form.Action.DirectSubmit
7534 * @class Ext.form.VTypes
7535 * <p>This is a singleton object which contains a set of commonly used field validation functions.
7536 * The validations provided are basic and intended to be easily customizable and extended.</p>
7537 * <p>To add custom VTypes specify the <code>{@link Ext.form.TextField#vtype vtype}</code> validation
7538 * test function, and optionally specify any corresponding error text to display and any keystroke
7539 * filtering mask to apply. For example:</p>
7541 // custom Vtype for vtype:'time'
7542 var timeTest = /^([1-9]|1[0-9]):([0-5][0-9])(\s[a|p]m)$/i;
7543 Ext.apply(Ext.form.VTypes, {
7544 // vtype validation function
7545 time: function(val, field) {
7546 return timeTest.test(val);
7548 // vtype Text property: The error text to display when the validation function returns false
7549 timeText: 'Not a valid time. Must be in the format "12:34 PM".',
7550 // vtype Mask property: The keystroke filter mask
7551 timeMask: /[\d\s:amp]/i
7556 // custom Vtype for vtype:'IPAddress'
7557 Ext.apply(Ext.form.VTypes, {
7558 IPAddress: function(v) {
7559 return /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(v);
7561 IPAddressText: 'Must be a numeric IP address',
7562 IPAddressMask: /[\d\.]/i
7567 Ext.form.VTypes = function(){
7568 // closure these in so they are only created once.
7569 var alpha = /^[a-zA-Z_]+$/;
7570 var alphanum = /^[a-zA-Z0-9_]+$/;
7571 var email = /^(\w+)([-+.][\w]+)*@(\w[-\w]*\.){1,5}([A-Za-z]){2,4}$/;
7572 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7574 // All these messages and functions are configurable
7577 * The function used to validate email addresses. Note that this is a very basic validation -- complete
7578 * validation per the email RFC specifications is very complex and beyond the scope of this class, although
7579 * this function can be overridden if a more comprehensive validation scheme is desired. See the validation
7580 * section of the <a href="http://en.wikipedia.org/wiki/E-mail_address">Wikipedia article on email addresses</a>
7581 * for additional information. This implementation is intended to validate the following emails:<tt>
7582 * 'barney@example.de', 'barney.rubble@example.com', 'barney-rubble@example.coop', 'barney+rubble@example.com'
7584 * @param {String} value The email address
7585 * @return {Boolean} true if the RegExp test passed, and false if not.
7587 'email' : function(v){
7588 return email.test(v);
7591 * The error text to display when the email validation function returns false. Defaults to:
7592 * <tt>'This field should be an e-mail address in the format "user@example.com"'</tt>
7595 'emailText' : 'This field should be an e-mail address in the format "user@example.com"',
7597 * The keystroke filter mask to be applied on email input. See the {@link #email} method for
7598 * information about more complex email validation. Defaults to:
7599 * <tt>/[a-z0-9_\.\-@]/i</tt>
7602 'emailMask' : /[a-z0-9_\.\-@]/i,
7605 * The function used to validate URLs
7606 * @param {String} value The URL
7607 * @return {Boolean} true if the RegExp test passed, and false if not.
7609 'url' : function(v){
7613 * The error text to display when the url validation function returns false. Defaults to:
7614 * <tt>'This field should be a URL in the format "http:/'+'/www.example.com"'</tt>
7617 'urlText' : 'This field should be a URL in the format "http:/'+'/www.example.com"',
7620 * The function used to validate alpha values
7621 * @param {String} value The value
7622 * @return {Boolean} true if the RegExp test passed, and false if not.
7624 'alpha' : function(v){
7625 return alpha.test(v);
7628 * The error text to display when the alpha validation function returns false. Defaults to:
7629 * <tt>'This field should only contain letters and _'</tt>
7632 'alphaText' : 'This field should only contain letters and _',
7634 * The keystroke filter mask to be applied on alpha input. Defaults to:
7635 * <tt>/[a-z_]/i</tt>
7638 'alphaMask' : /[a-z_]/i,
7641 * The function used to validate alphanumeric values
7642 * @param {String} value The value
7643 * @return {Boolean} true if the RegExp test passed, and false if not.
7645 'alphanum' : function(v){
7646 return alphanum.test(v);
7649 * The error text to display when the alphanumeric validation function returns false. Defaults to:
7650 * <tt>'This field should only contain letters, numbers and _'</tt>
7653 'alphanumText' : 'This field should only contain letters, numbers and _',
7655 * The keystroke filter mask to be applied on alphanumeric input. Defaults to:
7656 * <tt>/[a-z0-9_]/i</tt>
7659 'alphanumMask' : /[a-z0-9_]/i