3 * Copyright(c) 2006-2010 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 * <p>The label Element associated with this Field. <b>Only available after this Field has been rendered by a
19 * {@link form Ext.layout.FormLayout} layout manager.</b></p>
24 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password, file (defaults
25 * to 'text'). The types 'file' and 'password' must be used to render those field types currently -- there are
26 * no separate Ext components for those. Note that if you use <tt>inputType:'file'</tt>, {@link #emptyText}
27 * is not supported and should be avoided.
30 * @cfg {Number} tabIndex The tabIndex for this field. Note this only applies to fields that are rendered,
31 * not those which are built via applyTo (defaults to undefined).
34 * @cfg {Mixed} value A value to initialize this field with (defaults to undefined).
37 * @cfg {String} name The field's HTML name attribute (defaults to '').
38 * <b>Note</b>: this property must be set if this field is to be automatically included with
39 * {@link Ext.form.BasicForm#submit form submit()}.
42 * @cfg {String} cls A custom CSS class to apply to the field's underlying element (defaults to '').
46 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to 'x-form-invalid')
48 invalidClass : 'x-form-invalid',
50 * @cfg {String} invalidText The error text to use when marking a field invalid and no message is provided
51 * (defaults to 'The value in this field is invalid')
53 invalidText : 'The value in this field is invalid',
55 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to 'x-form-focus')
57 focusClass : 'x-form-focus',
59 * @cfg {Boolean} preventMark
60 * <tt>true</tt> to disable {@link #markInvalid marking the field invalid}.
61 * Defaults to <tt>false</tt>.
64 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
65 automatic validation (defaults to 'keyup').
67 validationEvent : 'keyup',
69 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
71 validateOnBlur : true,
73 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation
74 * is initiated (defaults to 250)
76 validationDelay : 250,
78 * @cfg {String/Object} autoCreate <p>A {@link Ext.DomHelper DomHelper} element spec, or true for a default
79 * element spec. Used to create the {@link Ext.Component#getEl Element} which will encapsulate this Component.
80 * See <tt>{@link Ext.Component#autoEl autoEl}</tt> for details. Defaults to:</p>
81 * <pre><code>{tag: 'input', type: 'text', size: '20', autocomplete: 'off'}</code></pre>
83 defaultAutoCreate : {tag: 'input', type: 'text', size: '20', autocomplete: 'off'},
85 * @cfg {String} fieldClass The default CSS class for the field (defaults to 'x-form-field')
87 fieldClass : 'x-form-field',
89 * @cfg {String} msgTarget<p>The location where the message text set through {@link #markInvalid} should display.
90 * Must be one of the following values:</p>
91 * <div class="mdetail-params"><ul>
92 * <li><code>qtip</code> Display a quick tip containing the message when the user hovers over the field. This is the default.
93 * <div class="subdesc"><b>{@link Ext.QuickTips#init Ext.QuickTips.init} must have been called for this setting to work.</b></div</li>
94 * <li><code>title</code> Display the message in a default browser title attribute popup.</li>
95 * <li><code>under</code> Add a block div beneath the field containing the error message.</li>
96 * <li><code>side</code> Add an error icon to the right of the field, displaying the message in a popup on hover.</li>
97 * <li><code>[element id]</code> Add the error message directly to the innerHTML of the specified element.</li>
102 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field
103 * (defaults to 'normal').
107 * @cfg {Boolean} readOnly <tt>true</tt> to mark the field as readOnly in HTML
108 * (defaults to <tt>false</tt>).
109 * <br><p><b>Note</b>: this only sets the element's readOnly DOM attribute.
110 * Setting <code>readOnly=true</code>, for example, will not disable triggering a
111 * ComboBox or DateField; it gives you the option of forcing the user to choose
112 * via the trigger without typing in the text box. To hide the trigger use
113 * <code>{@link Ext.form.TriggerField#hideTrigger hideTrigger}</code>.</p>
117 * @cfg {Boolean} disabled True to disable the field (defaults to false).
118 * <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>,
119 * disabled Fields will not be {@link Ext.form.BasicForm#submit submitted}.</p>
123 * @cfg {Boolean} submitValue False to clear the name attribute on the field so that it is not submitted during a form post.
124 * Defaults to <tt>true</tt>.
138 initComponent : function(){
139 Ext.form.Field.superclass.initComponent.call(this);
143 * Fires when this field receives input focus.
144 * @param {Ext.form.Field} this
149 * Fires when this field loses input focus.
150 * @param {Ext.form.Field} this
155 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.
156 * To handle other keys see {@link Ext.Panel#keys} or {@link Ext.KeyMap}.
157 * You can check {@link Ext.EventObject#getKey} to determine which key was pressed.
158 * For example: <pre><code>
159 var form = new Ext.form.FormPanel({
162 fieldLabel: 'Field 1',
166 fieldLabel: 'Field 2',
169 specialkey: function(field, e){
170 // e.HOME, e.END, e.PAGE_UP, e.PAGE_DOWN,
171 // e.TAB, e.ESC, arrow keys: e.LEFT, e.RIGHT, e.UP, e.DOWN
172 if (e.{@link Ext.EventObject#getKey getKey()} == e.ENTER) {
173 var form = field.ownerCt.getForm();
183 * @param {Ext.form.Field} this
184 * @param {Ext.EventObject} e The event object
189 * Fires just before the field blurs if the field value has changed.
190 * @param {Ext.form.Field} this
191 * @param {Mixed} newValue The new value
192 * @param {Mixed} oldValue The original value
197 * Fires after the field has been marked as invalid.
198 * @param {Ext.form.Field} this
199 * @param {String} msg The validation message
204 * Fires after the field has been validated with no errors.
205 * @param {Ext.form.Field} this
212 * Returns the {@link Ext.form.Field#name name} or {@link Ext.form.ComboBox#hiddenName hiddenName}
213 * attribute of the field if available.
214 * @return {String} name The field {@link Ext.form.Field#name name} or {@link Ext.form.ComboBox#hiddenName hiddenName}
216 getName : function(){
217 return this.rendered && this.el.dom.name ? this.el.dom.name : this.name || this.id || '';
221 onRender : function(ct, position){
223 var cfg = this.getAutoCreate();
226 cfg.name = this.name || this.id;
229 cfg.type = this.inputType;
233 Ext.form.Field.superclass.onRender.call(this, ct, position);
234 if(this.submitValue === false){
235 this.el.dom.removeAttribute('name');
237 var type = this.el.dom.type;
239 if(type == 'password'){
242 this.el.addClass('x-form-'+type);
245 this.setReadOnly(true);
247 if(this.tabIndex !== undefined){
248 this.el.dom.setAttribute('tabIndex', this.tabIndex);
251 this.el.addClass([this.fieldClass, this.cls]);
255 getItemCt : function(){
260 initValue : function(){
261 if(this.value !== undefined){
262 this.setValue(this.value);
263 }else if(!Ext.isEmpty(this.el.dom.value) && this.el.dom.value != this.emptyText){
264 this.setValue(this.el.dom.value);
267 * The original value of the field as configured in the {@link #value} configuration, or
268 * as loaded by the last form load operation if the form's {@link Ext.form.BasicForm#trackResetOnLoad trackResetOnLoad}
269 * setting is <code>true</code>.
271 * @property originalValue
273 this.originalValue = this.getValue();
277 * <p>Returns true if the value of this Field has been changed from its original value.
278 * Will return false if the field is disabled or has not been rendered yet.</p>
279 * <p>Note that if the owning {@link Ext.form.BasicForm form} was configured with
280 * {@link Ext.form.BasicForm}.{@link Ext.form.BasicForm#trackResetOnLoad trackResetOnLoad}
281 * then the <i>original value</i> is updated when the values are loaded by
282 * {@link Ext.form.BasicForm}.{@link Ext.form.BasicForm#setValues setValues}.</p>
283 * @return {Boolean} True if this field has been changed from its original value (and
284 * is not disabled), false otherwise.
286 isDirty : function() {
287 if(this.disabled || !this.rendered) {
290 return String(this.getValue()) !== String(this.originalValue);
294 * Sets the read only state of this field.
295 * @param {Boolean} readOnly Whether the field should be read only.
297 setReadOnly : function(readOnly){
299 this.el.dom.readOnly = readOnly;
301 this.readOnly = readOnly;
305 afterRender : function(){
306 Ext.form.Field.superclass.afterRender.call(this);
312 fireKey : function(e){
313 if(e.isSpecialKey()){
314 this.fireEvent('specialkey', this, e);
319 * Resets the current field value to the originally loaded value and clears any validation messages.
320 * See {@link Ext.form.BasicForm}.{@link Ext.form.BasicForm#trackResetOnLoad trackResetOnLoad}
323 this.setValue(this.originalValue);
328 initEvents : function(){
329 this.mon(this.el, Ext.EventManager.useKeydown ? 'keydown' : 'keypress', this.fireKey, this);
330 this.mon(this.el, 'focus', this.onFocus, this);
332 // standardise buffer across all browsers + OS-es for consistent event order.
333 // (the 10ms buffer for Editors fixes a weird FF/Win editor issue when changing OS window focus)
334 this.mon(this.el, 'blur', this.onBlur, this, this.inEditor ? {buffer:10} : null);
338 preFocus: Ext.emptyFn,
341 onFocus : function(){
344 this.el.addClass(this.focusClass);
347 this.hasFocus = true;
349 * <p>The value that the Field had at the time it was last focused. This is the value that is passed
350 * to the {@link #change} event which is fired if the value has been changed when the Field is blurred.</p>
351 * <p><b>This will be undefined until the Field has been visited.</b> Compare {@link #originalValue}.</p>
353 * @property startValue
355 this.startValue = this.getValue();
356 this.fireEvent('focus', this);
361 beforeBlur : Ext.emptyFn,
367 this.el.removeClass(this.focusClass);
369 this.hasFocus = false;
370 if(this.validationEvent !== false && (this.validateOnBlur || this.validationEvent == 'blur')){
373 var v = this.getValue();
374 if(String(v) !== String(this.startValue)){
375 this.fireEvent('change', this, v, this.startValue);
377 this.fireEvent('blur', this);
382 postBlur : Ext.emptyFn,
385 * Returns whether or not the field value is currently valid by
386 * {@link #validateValue validating} the {@link #processValue processed value}
387 * of the field. <b>Note</b>: {@link #disabled} fields are ignored.
388 * @param {Boolean} preventMark True to disable marking the field invalid
389 * @return {Boolean} True if the value is valid, else false
391 isValid : function(preventMark){
395 var restore = this.preventMark;
396 this.preventMark = preventMark === true;
397 var v = this.validateValue(this.processValue(this.getRawValue()));
398 this.preventMark = restore;
403 * Validates the field value
404 * @return {Boolean} True if the value is valid, else false
406 validate : function(){
407 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
415 * This method should only be overridden if necessary to prepare raw values
416 * for validation (see {@link #validate} and {@link #isValid}). This method
417 * is expected to return the processed value for the field which will
418 * be used for validation (see validateValue method).
419 * @param {Mixed} value
421 processValue : function(value){
427 * Subclasses should provide the validation implementation by overriding this
428 * @param {Mixed} value
430 validateValue : function(value){
435 * Gets the active error message for this field.
436 * @return {String} Returns the active error message on the field, if there is no error, an empty string is returned.
438 getActiveError : function(){
439 return this.activeError || '';
443 * <p>Display an error message associated with this field, using {@link #msgTarget} to determine how to
444 * display the message and applying {@link #invalidClass} to the field's UI element.</p>
445 * <p><b>Note</b>: this method does not cause the Field's {@link #validate} method to return <code>false</code>
446 * if the value does <i>pass</i> validation. So simply marking a Field as invalid will not prevent
447 * submission of forms submitted with the {@link Ext.form.Action.Submit#clientValidation} option set.</p>
448 * {@link #isValid invalid}.
449 * @param {String} msg (optional) The validation message (defaults to {@link #invalidText})
451 markInvalid : function(msg){
452 if(!this.rendered || this.preventMark){ // not rendered
455 msg = msg || this.invalidText;
457 var mt = this.getMessageHandler();
460 }else if(this.msgTarget){
461 this.el.addClass(this.invalidClass);
462 var t = Ext.getDom(this.msgTarget);
465 t.style.display = this.msgDisplay;
468 this.activeError = msg;
469 this.fireEvent('invalid', this, msg);
473 * Clear any invalid styles/messages for this field
475 clearInvalid : function(){
476 if(!this.rendered || this.preventMark){ // not rendered
479 this.el.removeClass(this.invalidClass);
480 var mt = this.getMessageHandler();
483 }else if(this.msgTarget){
484 this.el.removeClass(this.invalidClass);
485 var t = Ext.getDom(this.msgTarget);
488 t.style.display = 'none';
491 delete this.activeError;
492 this.fireEvent('valid', this);
496 getMessageHandler : function(){
497 return Ext.form.MessageTargets[this.msgTarget];
501 getErrorCt : function(){
502 return this.el.findParent('.x-form-element', 5, true) || // use form element wrap if available
503 this.el.findParent('.x-form-field-wrap', 5, true); // else direct field wrap
506 // Alignment for 'under' target
507 alignErrorEl : function(){
508 this.errorEl.setWidth(this.getErrorCt().getWidth(true) - 20);
511 // Alignment for 'side' target
512 alignErrorIcon : function(){
513 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
517 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
518 * @return {Mixed} value The field value
520 getRawValue : function(){
521 var v = this.rendered ? this.el.getValue() : Ext.value(this.value, '');
522 if(v === this.emptyText){
529 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
530 * @return {Mixed} value The field value
532 getValue : function(){
536 var v = this.el.getValue();
537 if(v === this.emptyText || v === undefined){
544 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
545 * @param {Mixed} value The value to set
546 * @return {Mixed} value The field value that is set
548 setRawValue : function(v){
549 return this.rendered ? (this.el.dom.value = (Ext.isEmpty(v) ? '' : v)) : '';
553 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
554 * @param {Mixed} value The value to set
555 * @return {Ext.form.Field} this
557 setValue : function(v){
560 this.el.dom.value = (Ext.isEmpty(v) ? '' : v);
566 // private, does not work for all fields
567 append : function(v){
568 this.setValue([this.getValue(), v].join(''));
572 * @cfg {Boolean} autoWidth @hide
575 * @cfg {Boolean} autoHeight @hide
579 * @cfg {String} autoEl @hide
584 Ext.form.MessageTargets = {
586 mark: function(field, msg){
587 field.el.addClass(field.invalidClass);
588 field.el.dom.qtip = msg;
589 field.el.dom.qclass = 'x-form-invalid-tip';
590 if(Ext.QuickTips){ // fix for floating editors interacting with DND
591 Ext.QuickTips.enable();
594 clear: function(field){
595 field.el.removeClass(field.invalidClass);
596 field.el.dom.qtip = '';
600 mark: function(field, msg){
601 field.el.addClass(field.invalidClass);
602 field.el.dom.title = msg;
604 clear: function(field){
605 field.el.dom.title = '';
609 mark: function(field, msg){
610 field.el.addClass(field.invalidClass);
612 var elp = field.getErrorCt();
613 if(!elp){ // field has no container el
614 field.el.dom.title = msg;
617 field.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
618 field.on('resize', field.alignErrorEl, field);
619 field.on('destroy', function(){
620 Ext.destroy(this.errorEl);
623 field.alignErrorEl();
624 field.errorEl.update(msg);
625 Ext.form.Field.msgFx[field.msgFx].show(field.errorEl, field);
627 clear: function(field){
628 field.el.removeClass(field.invalidClass);
630 Ext.form.Field.msgFx[field.msgFx].hide(field.errorEl, field);
632 field.el.dom.title = '';
637 mark: function(field, msg){
638 field.el.addClass(field.invalidClass);
639 if(!field.errorIcon){
640 var elp = field.getErrorCt();
641 if(!elp){ // field has no container el
642 field.el.dom.title = msg;
645 field.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
646 field.on('resize', field.alignErrorIcon, field);
647 field.on('destroy', function(){
648 Ext.destroy(this.errorIcon);
651 field.alignErrorIcon();
652 field.errorIcon.dom.qtip = msg;
653 field.errorIcon.dom.qclass = 'x-form-invalid-tip';
654 field.errorIcon.show();
656 clear: function(field){
657 field.el.removeClass(field.invalidClass);
659 field.errorIcon.dom.qtip = '';
660 field.errorIcon.hide();
662 field.el.dom.title = '';
668 // anything other than normal should be considered experimental
669 Ext.form.Field.msgFx = {
671 show: function(msgEl, f){
672 msgEl.setDisplayed('block');
675 hide : function(msgEl, f){
676 msgEl.setDisplayed(false).update('');
681 show: function(msgEl, f){
682 msgEl.slideIn('t', {stopFx:true});
685 hide : function(msgEl, f){
686 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
691 show: function(msgEl, f){
693 msgEl.alignTo(f.el, 'tl-tr');
694 msgEl.slideIn('l', {stopFx:true});
697 hide : function(msgEl, f){
698 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
702 Ext.reg('field', Ext.form.Field);
704 * @class Ext.form.TextField
705 * @extends Ext.form.Field
706 * <p>Basic text field. Can be used as a direct replacement for traditional text inputs,
707 * or as the base class for more sophisticated input controls (like {@link Ext.form.TextArea}
708 * and {@link Ext.form.ComboBox}).</p>
709 * <p><b><u>Validation</u></b></p>
710 * <p>The validation procedure is described in the documentation for {@link #validateValue}.</p>
711 * <p><b><u>Alter Validation Behavior</u></b></p>
712 * <p>Validation behavior for each field can be configured:</p>
713 * <div class="mdetail-params"><ul>
714 * <li><code>{@link Ext.form.TextField#invalidText invalidText}</code> : the default validation message to
715 * show if any validation step above does not provide a message when invalid</li>
716 * <li><code>{@link Ext.form.TextField#maskRe maskRe}</code> : filter out keystrokes before any validation occurs</li>
717 * <li><code>{@link Ext.form.TextField#stripCharsRe stripCharsRe}</code> : filter characters after being typed in,
718 * but before being validated</li>
719 * <li><code>{@link Ext.form.Field#invalidClass invalidClass}</code> : alternate style when invalid</li>
720 * <li><code>{@link Ext.form.Field#validateOnBlur validateOnBlur}</code>,
721 * <code>{@link Ext.form.Field#validationDelay validationDelay}</code>, and
722 * <code>{@link Ext.form.Field#validationEvent validationEvent}</code> : modify how/when validation is triggered</li>
725 * @constructor Creates a new TextField
726 * @param {Object} config Configuration options
730 Ext.form.TextField = Ext.extend(Ext.form.Field, {
732 * @cfg {String} vtypeText A custom error message to display in place of the default message provided
733 * for the <b><code>{@link #vtype}</code></b> currently set for this field (defaults to <tt>''</tt>). <b>Note</b>:
734 * only applies if <b><code>{@link #vtype}</code></b> is set, else ignored.
737 * @cfg {RegExp} stripCharsRe A JavaScript RegExp object used to strip unwanted content from the value
738 * before validation (defaults to <tt>null</tt>).
741 * @cfg {Boolean} grow <tt>true</tt> if this field should automatically grow and shrink to its content
742 * (defaults to <tt>false</tt>)
746 * @cfg {Number} growMin The minimum width to allow when <code><b>{@link #grow}</b> = true</code> (defaults
751 * @cfg {Number} growMax The maximum width to allow when <code><b>{@link #grow}</b> = true</code> (defaults
756 * @cfg {String} vtype A validation type name as defined in {@link Ext.form.VTypes} (defaults to <tt>null</tt>)
760 * @cfg {RegExp} maskRe An input mask regular expression that will be used to filter keystrokes that do
761 * not match (defaults to <tt>null</tt>)
765 * @cfg {Boolean} disableKeyFilter Specify <tt>true</tt> to disable input keystroke filtering (defaults
768 disableKeyFilter : false,
770 * @cfg {Boolean} allowBlank Specify <tt>false</tt> to validate that the value's length is > 0 (defaults to
775 * @cfg {Number} minLength Minimum input field length required (defaults to <tt>0</tt>)
779 * @cfg {Number} maxLength Maximum input field length allowed by validation (defaults to Number.MAX_VALUE).
780 * This behavior is intended to provide instant feedback to the user by improving usability to allow pasting
781 * and editing or overtyping and back tracking. To restrict the maximum number of characters that can be
782 * entered into the field use <tt><b>{@link Ext.form.Field#autoCreate autoCreate}</b></tt> to add
783 * any attributes you want to a field, for example:<pre><code>
784 var myField = new Ext.form.NumberField({
787 fieldLabel: 'Mobile',
788 maxLength: 16, // for validation
789 autoCreate: {tag: 'input', type: 'text', size: '20', autocomplete: 'off', maxlength: '10'}
793 maxLength : Number.MAX_VALUE,
795 * @cfg {String} minLengthText Error text to display if the <b><tt>{@link #minLength minimum length}</tt></b>
796 * validation fails (defaults to <tt>'The minimum length for this field is {minLength}'</tt>)
798 minLengthText : 'The minimum length for this field is {0}',
800 * @cfg {String} maxLengthText Error text to display if the <b><tt>{@link #maxLength maximum length}</tt></b>
801 * validation fails (defaults to <tt>'The maximum length for this field is {maxLength}'</tt>)
803 maxLengthText : 'The maximum length for this field is {0}',
805 * @cfg {Boolean} selectOnFocus <tt>true</tt> to automatically select any existing field text when the field
806 * receives input focus (defaults to <tt>false</tt>)
808 selectOnFocus : false,
810 * @cfg {String} blankText The error text to display if the <b><tt>{@link #allowBlank}</tt></b> validation
811 * fails (defaults to <tt>'This field is required'</tt>)
813 blankText : 'This field is required',
815 * @cfg {Function} validator
816 * <p>A custom validation function to be called during field validation ({@link #validateValue})
817 * (defaults to <tt>null</tt>). If specified, this function will be called first, allowing the
818 * developer to override the default validation process.</p>
819 * <br><p>This function will be passed the following Parameters:</p>
820 * <div class="mdetail-params"><ul>
821 * <li><code>value</code>: <i>Mixed</i>
822 * <div class="sub-desc">The current field value</div></li>
824 * <br><p>This function is to Return:</p>
825 * <div class="mdetail-params"><ul>
826 * <li><code>true</code>: <i>Boolean</i>
827 * <div class="sub-desc"><code>true</code> if the value is valid</div></li>
828 * <li><code>msg</code>: <i>String</i>
829 * <div class="sub-desc">An error message if the value is invalid</div></li>
834 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation
835 * (defaults to <tt>null</tt>). If the test fails, the field will be marked invalid using
836 * <b><tt>{@link #regexText}</tt></b>.
840 * @cfg {String} regexText The error text to display if <b><tt>{@link #regex}</tt></b> is used and the
841 * test fails during validation (defaults to <tt>''</tt>)
845 * @cfg {String} emptyText The default text to place into an empty field (defaults to <tt>null</tt>).
846 * <b>Note</b>: that this value will be submitted to the server if this field is enabled and configured
847 * with a {@link #name}.
851 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the <b><tt>{@link #emptyText}</tt></b>
852 * (defaults to <tt>'x-form-empty-field'</tt>). This class is automatically added and removed as needed
853 * depending on the current field value.
855 emptyClass : 'x-form-empty-field',
858 * @cfg {Boolean} enableKeyEvents <tt>true</tt> to enable the proxying of key events for the HTML input
859 * field (defaults to <tt>false</tt>)
862 initComponent : function(){
863 Ext.form.TextField.superclass.initComponent.call(this);
867 * Fires when the <tt><b>{@link #autoSize}</b></tt> function is triggered. The field may or
868 * may not have actually changed size according to the default logic, but this event provides
869 * a hook for the developer to apply additional logic at runtime to resize the field if needed.
870 * @param {Ext.form.Field} this This text field
871 * @param {Number} width The new field width
877 * Keydown input field event. This event only fires if <tt><b>{@link #enableKeyEvents}</b></tt>
879 * @param {Ext.form.TextField} this This text field
880 * @param {Ext.EventObject} e
885 * Keyup input field event. This event only fires if <tt><b>{@link #enableKeyEvents}</b></tt>
887 * @param {Ext.form.TextField} this This text field
888 * @param {Ext.EventObject} e
893 * Keypress input field event. This event only fires if <tt><b>{@link #enableKeyEvents}</b></tt>
895 * @param {Ext.form.TextField} this This text field
896 * @param {Ext.EventObject} e
903 initEvents : function(){
904 Ext.form.TextField.superclass.initEvents.call(this);
905 if(this.validationEvent == 'keyup'){
906 this.validationTask = new Ext.util.DelayedTask(this.validate, this);
907 this.mon(this.el, 'keyup', this.filterValidation, this);
909 else if(this.validationEvent !== false && this.validationEvent != 'blur'){
910 this.mon(this.el, this.validationEvent, this.validate, this, {buffer: this.validationDelay});
912 if(this.selectOnFocus || this.emptyText){
913 this.mon(this.el, 'mousedown', this.onMouseDown, this);
916 this.applyEmptyText();
919 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Ext.form.VTypes[this.vtype+'Mask']))){
920 this.mon(this.el, 'keypress', this.filterKeys, this);
923 this.mon(this.el, 'keyup', this.onKeyUpBuffered, this, {buffer: 50});
924 this.mon(this.el, 'click', this.autoSize, this);
926 if(this.enableKeyEvents){
930 keydown: this.onKeyDown,
931 keypress: this.onKeyPress
936 onMouseDown: function(e){
938 this.mon(this.el, 'mouseup', Ext.emptyFn, this, { single: true, preventDefault: true });
942 processValue : function(value){
943 if(this.stripCharsRe){
944 var newValue = value.replace(this.stripCharsRe, '');
945 if(newValue !== value){
946 this.setRawValue(newValue);
953 filterValidation : function(e){
954 if(!e.isNavKeyPress()){
955 this.validationTask.delay(this.validationDelay);
960 onDisable: function(){
961 Ext.form.TextField.superclass.onDisable.call(this);
963 this.el.dom.unselectable = 'on';
968 onEnable: function(){
969 Ext.form.TextField.superclass.onEnable.call(this);
971 this.el.dom.unselectable = '';
976 onKeyUpBuffered : function(e){
977 if(this.doAutoSize(e)){
983 doAutoSize : function(e){
984 return !e.isNavKeyPress();
988 onKeyUp : function(e){
989 this.fireEvent('keyup', this, e);
993 onKeyDown : function(e){
994 this.fireEvent('keydown', this, e);
998 onKeyPress : function(e){
999 this.fireEvent('keypress', this, e);
1003 * Resets the current field value to the originally-loaded value and clears any validation messages.
1004 * Also adds <tt><b>{@link #emptyText}</b></tt> and <tt><b>{@link #emptyClass}</b></tt> if the
1005 * original value was blank.
1008 Ext.form.TextField.superclass.reset.call(this);
1009 this.applyEmptyText();
1012 applyEmptyText : function(){
1013 if(this.rendered && this.emptyText && this.getRawValue().length < 1 && !this.hasFocus){
1014 this.setRawValue(this.emptyText);
1015 this.el.addClass(this.emptyClass);
1020 preFocus : function(){
1023 if(el.dom.value == this.emptyText){
1024 this.setRawValue('');
1026 el.removeClass(this.emptyClass);
1028 if(this.selectOnFocus){
1034 postBlur : function(){
1035 this.applyEmptyText();
1039 filterKeys : function(e){
1044 if(Ext.isGecko && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
1047 var cc = String.fromCharCode(e.getCharCode());
1048 if(!Ext.isGecko && e.isSpecialKey() && !cc){
1051 if(!this.maskRe.test(cc)){
1056 setValue : function(v){
1057 if(this.emptyText && this.el && !Ext.isEmpty(v)){
1058 this.el.removeClass(this.emptyClass);
1060 Ext.form.TextField.superclass.setValue.apply(this, arguments);
1061 this.applyEmptyText();
1067 * <p>Validates a value according to the field's validation rules and marks the field as invalid
1068 * if the validation fails. Validation rules are processed in the following order:</p>
1069 * <div class="mdetail-params"><ul>
1071 * <li><b>1. Field specific validator</b>
1072 * <div class="sub-desc">
1073 * <p>A validator offers a way to customize and reuse a validation specification.
1074 * If a field is configured with a <code>{@link #validator}</code>
1075 * function, it will be passed the current field value. The <code>{@link #validator}</code>
1076 * function is expected to return either:
1077 * <div class="mdetail-params"><ul>
1078 * <li>Boolean <tt>true</tt> if the value is valid (validation continues).</li>
1079 * <li>a String to represent the invalid message if invalid (validation halts).</li>
1083 * <li><b>2. Basic Validation</b>
1084 * <div class="sub-desc">
1085 * <p>If the <code>{@link #validator}</code> has not halted validation,
1086 * basic validation proceeds as follows:</p>
1088 * <div class="mdetail-params"><ul>
1090 * <li><code>{@link #allowBlank}</code> : (Invalid message =
1091 * <code>{@link #emptyText}</code>)<div class="sub-desc">
1092 * Depending on the configuration of <code>{@link #allowBlank}</code>, a
1093 * blank field will cause validation to halt at this step and return
1094 * Boolean true or false accordingly.
1097 * <li><code>{@link #minLength}</code> : (Invalid message =
1098 * <code>{@link #minLengthText}</code>)<div class="sub-desc">
1099 * If the passed value does not satisfy the <code>{@link #minLength}</code>
1100 * specified, validation halts.
1103 * <li><code>{@link #maxLength}</code> : (Invalid message =
1104 * <code>{@link #maxLengthText}</code>)<div class="sub-desc">
1105 * If the passed value does not satisfy the <code>{@link #maxLength}</code>
1106 * specified, validation halts.
1112 * <li><b>3. Preconfigured Validation Types (VTypes)</b>
1113 * <div class="sub-desc">
1114 * <p>If none of the prior validation steps halts validation, a field
1115 * configured with a <code>{@link #vtype}</code> will utilize the
1116 * corresponding {@link Ext.form.VTypes VTypes} validation function.
1117 * If invalid, either the field's <code>{@link #vtypeText}</code> or
1118 * the VTypes vtype Text property will be used for the invalid message.
1119 * Keystrokes on the field will be filtered according to the VTypes
1120 * vtype Mask property.</p>
1123 * <li><b>4. Field specific regex test</b>
1124 * <div class="sub-desc">
1125 * <p>If none of the prior validation steps halts validation, a field's
1126 * configured <code>{@link #regex}</code> test will be processed.
1127 * The invalid message for this test is configured with
1128 * <code>{@link #regexText}</code>.</p>
1131 * @param {Mixed} value The value to validate
1132 * @return {Boolean} True if the value is valid, else false
1134 validateValue : function(value){
1135 if(Ext.isFunction(this.validator)){
1136 var msg = this.validator(value);
1138 this.markInvalid(msg);
1142 if(value.length < 1 || value === this.emptyText){ // if it's blank
1143 if(this.allowBlank){
1144 this.clearInvalid();
1147 this.markInvalid(this.blankText);
1151 if(value.length < this.minLength){
1152 this.markInvalid(String.format(this.minLengthText, this.minLength));
1155 if(value.length > this.maxLength){
1156 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
1160 var vt = Ext.form.VTypes;
1161 if(!vt[this.vtype](value, this)){
1162 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
1166 if(this.regex && !this.regex.test(value)){
1167 this.markInvalid(this.regexText);
1174 * Selects text in this field
1175 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
1176 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
1178 selectText : function(start, end){
1179 var v = this.getRawValue();
1180 var doFocus = false;
1182 start = start === undefined ? 0 : start;
1183 end = end === undefined ? v.length : end;
1184 var d = this.el.dom;
1185 if(d.setSelectionRange){
1186 d.setSelectionRange(start, end);
1187 }else if(d.createTextRange){
1188 var range = d.createTextRange();
1189 range.moveStart('character', start);
1190 range.moveEnd('character', end-v.length);
1193 doFocus = Ext.isGecko || Ext.isOpera;
1203 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
1204 * This only takes effect if <tt><b>{@link #grow}</b> = true</tt>, and fires the {@link #autosize} event.
1206 autoSize : function(){
1207 if(!this.grow || !this.rendered){
1211 this.metrics = Ext.util.TextMetrics.createInstance(this.el);
1214 var v = el.dom.value;
1215 var d = document.createElement('div');
1216 d.appendChild(document.createTextNode(v));
1221 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
1222 this.el.setWidth(w);
1223 this.fireEvent('autosize', this, w);
1226 onDestroy: function(){
1227 if(this.validationTask){
1228 this.validationTask.cancel();
1229 this.validationTask = null;
1231 Ext.form.TextField.superclass.onDestroy.call(this);
1234 Ext.reg('textfield', Ext.form.TextField);
1236 * @class Ext.form.TriggerField
1237 * @extends Ext.form.TextField
1238 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
1239 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
1240 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
1241 * for which you can provide a custom implementation. For example:
1243 var trigger = new Ext.form.TriggerField();
1244 trigger.onTriggerClick = myTriggerFn;
1245 trigger.applyToMarkup('my-field');
1248 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
1249 * {@link Ext.form.DateField} and {@link Ext.form.ComboBox} are perfect examples of this.
1252 * Create a new TriggerField.
1253 * @param {Object} config Configuration options (valid {@Ext.form.TextField} config options will also be applied
1254 * to the base TextField)
1257 Ext.form.TriggerField = Ext.extend(Ext.form.TextField, {
1259 * @cfg {String} triggerClass
1260 * An additional CSS class used to style the trigger button. The trigger will always get the
1261 * class <tt>'x-form-trigger'</tt> by default and <tt>triggerClass</tt> will be <b>appended</b> if specified.
1264 * @cfg {Mixed} triggerConfig
1265 * <p>A {@link Ext.DomHelper DomHelper} config object specifying the structure of the
1266 * trigger element for this Field. (Optional).</p>
1267 * <p>Specify this when you need a customized element to act as the trigger button for a TriggerField.</p>
1268 * <p>Note that when using this option, it is the developer's responsibility to ensure correct sizing, positioning
1269 * and appearance of the trigger. Defaults to:</p>
1270 * <pre><code>{tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass}</code></pre>
1273 * @cfg {String/Object} autoCreate <p>A {@link Ext.DomHelper DomHelper} element spec, or true for a default
1274 * element spec. Used to create the {@link Ext.Component#getEl Element} which will encapsulate this Component.
1275 * See <tt>{@link Ext.Component#autoEl autoEl}</tt> for details. Defaults to:</p>
1276 * <pre><code>{tag: "input", type: "text", size: "16", autocomplete: "off"}</code></pre>
1278 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
1280 * @cfg {Boolean} hideTrigger <tt>true</tt> to hide the trigger element and display only the base
1281 * text field (defaults to <tt>false</tt>)
1285 * @cfg {Boolean} editable <tt>false</tt> to prevent the user from typing text directly into the field,
1286 * the field will only respond to a click on the trigger to set the value. (defaults to <tt>true</tt>).
1290 * @cfg {Boolean} readOnly <tt>true</tt> to prevent the user from changing the field, and
1291 * hides the trigger. Superceeds the editable and hideTrigger options if the value is true.
1292 * (defaults to <tt>false</tt>)
1296 * @cfg {String} wrapFocusClass The class added to the to the wrap of the trigger element. Defaults to
1297 * <tt>x-trigger-wrap-focus</tt>.
1299 wrapFocusClass: 'x-trigger-wrap-focus',
1304 autoSize: Ext.emptyFn,
1314 defaultTriggerWidth: 17,
1317 onResize : function(w, h){
1318 Ext.form.TriggerField.superclass.onResize.call(this, w, h);
1319 var tw = this.getTriggerWidth();
1320 if(Ext.isNumber(w)){
1321 this.el.setWidth(w - tw);
1323 this.wrap.setWidth(this.el.getWidth() + tw);
1326 getTriggerWidth: function(){
1327 var tw = this.trigger.getWidth();
1328 if(!this.hideTrigger && tw === 0){
1329 tw = this.defaultTriggerWidth;
1335 alignErrorIcon : function(){
1337 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
1342 onRender : function(ct, position){
1343 this.doc = Ext.isIE ? Ext.getBody() : Ext.getDoc();
1344 Ext.form.TriggerField.superclass.onRender.call(this, ct, position);
1346 this.wrap = this.el.wrap({cls: 'x-form-field-wrap x-form-field-trigger-wrap'});
1347 this.trigger = this.wrap.createChild(this.triggerConfig ||
1348 {tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
1351 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
1353 this.resizeEl = this.positionEl = this.wrap;
1356 updateEditState: function(){
1358 if (this.readOnly) {
1359 this.el.dom.readOnly = true;
1360 this.el.addClass('x-trigger-noedit');
1361 this.mun(this.el, 'click', this.onTriggerClick, this);
1362 this.trigger.setDisplayed(false);
1364 if (!this.editable) {
1365 this.el.dom.readOnly = true;
1366 this.el.addClass('x-trigger-noedit');
1367 this.mon(this.el, 'click', this.onTriggerClick, this);
1369 this.el.dom.readOnly = false;
1370 this.el.removeClass('x-trigger-noedit');
1371 this.mun(this.el, 'click', this.onTriggerClick, this);
1373 this.trigger.setDisplayed(!this.hideTrigger);
1375 this.onResize(this.width || this.wrap.getWidth());
1379 setHideTrigger: function(hideTrigger){
1380 if(hideTrigger != this.hideTrigger){
1381 this.hideTrigger = hideTrigger;
1382 this.updateEditState();
1387 * @param {Boolean} value True to allow the user to directly edit the field text
1388 * Allow or prevent the user from directly editing the field text. If false is passed,
1389 * the user will only be able to modify the field using the trigger. Will also add
1390 * a click event to the text field which will call the trigger. This method
1391 * is the runtime equivalent of setting the 'editable' config option at config time.
1393 setEditable: function(editable){
1394 if(editable != this.editable){
1395 this.editable = editable;
1396 this.updateEditState();
1401 * @param {Boolean} value True to prevent the user changing the field and explicitly
1403 * Setting this to true will superceed settings editable and hideTrigger.
1404 * Setting this to false will defer back to editable and hideTrigger. This method
1405 * is the runtime equivalent of setting the 'readOnly' config option at config time.
1407 setReadOnly: function(readOnly){
1408 if(readOnly != this.readOnly){
1409 this.readOnly = readOnly;
1410 this.updateEditState();
1414 afterRender : function(){
1415 Ext.form.TriggerField.superclass.afterRender.call(this);
1416 this.updateEditState();
1420 initTrigger : function(){
1421 this.mon(this.trigger, 'click', this.onTriggerClick, this, {preventDefault:true});
1422 this.trigger.addClassOnOver('x-form-trigger-over');
1423 this.trigger.addClassOnClick('x-form-trigger-click');
1427 onDestroy : function(){
1428 Ext.destroy(this.trigger, this.wrap);
1430 this.doc.un('mousedown', this.mimicBlur, this);
1433 Ext.form.TriggerField.superclass.onDestroy.call(this);
1437 onFocus : function(){
1438 Ext.form.TriggerField.superclass.onFocus.call(this);
1440 this.wrap.addClass(this.wrapFocusClass);
1441 this.mimicing = true;
1442 this.doc.on('mousedown', this.mimicBlur, this, {delay: 10});
1443 if(this.monitorTab){
1444 this.on('specialkey', this.checkTab, this);
1450 checkTab : function(me, e){
1451 if(e.getKey() == e.TAB){
1457 onBlur : Ext.emptyFn,
1460 mimicBlur : function(e){
1461 if(!this.isDestroyed && !this.wrap.contains(e.target) && this.validateBlur(e)){
1467 triggerBlur : function(){
1468 this.mimicing = false;
1469 this.doc.un('mousedown', this.mimicBlur, this);
1470 if(this.monitorTab && this.el){
1471 this.un('specialkey', this.checkTab, this);
1473 Ext.form.TriggerField.superclass.onBlur.call(this);
1475 this.wrap.removeClass(this.wrapFocusClass);
1479 beforeBlur : Ext.emptyFn,
1482 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
1483 validateBlur : function(e){
1488 * The function that should handle the trigger's click event. This method does nothing by default
1489 * until overridden by an implementing function. See Ext.form.ComboBox and Ext.form.DateField for
1490 * sample implementations.
1492 * @param {EventObject} e
1494 onTriggerClick : Ext.emptyFn
1497 * @cfg {Boolean} grow @hide
1500 * @cfg {Number} growMin @hide
1503 * @cfg {Number} growMax @hide
1508 * @class Ext.form.TwinTriggerField
1509 * @extends Ext.form.TriggerField
1510 * TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
1511 * to be extended by an implementing class. For an example of implementing this class, see the custom
1512 * SearchField implementation here:
1513 * <a href="http://extjs.com/deploy/ext/examples/form/custom.html">http://extjs.com/deploy/ext/examples/form/custom.html</a>
1515 Ext.form.TwinTriggerField = Ext.extend(Ext.form.TriggerField, {
1517 * @cfg {Mixed} triggerConfig
1518 * <p>A {@link Ext.DomHelper DomHelper} config object specifying the structure of the trigger elements
1519 * for this Field. (Optional).</p>
1520 * <p>Specify this when you need a customized element to contain the two trigger elements for this Field.
1521 * Each trigger element must be marked by the CSS class <tt>x-form-trigger</tt> (also see
1522 * <tt>{@link #trigger1Class}</tt> and <tt>{@link #trigger2Class}</tt>).</p>
1523 * <p>Note that when using this option, it is the developer's responsibility to ensure correct sizing,
1524 * positioning and appearance of the triggers.</p>
1527 * @cfg {String} trigger1Class
1528 * An additional CSS class used to style the trigger button. The trigger will always get the
1529 * class <tt>'x-form-trigger'</tt> by default and <tt>triggerClass</tt> will be <b>appended</b> if specified.
1532 * @cfg {String} trigger2Class
1533 * An additional CSS class used to style the trigger button. The trigger will always get the
1534 * class <tt>'x-form-trigger'</tt> by default and <tt>triggerClass</tt> will be <b>appended</b> if specified.
1537 initComponent : function(){
1538 Ext.form.TwinTriggerField.superclass.initComponent.call(this);
1540 this.triggerConfig = {
1541 tag:'span', cls:'x-form-twin-triggers', cn:[
1542 {tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
1543 {tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
1547 getTrigger : function(index){
1548 return this.triggers[index];
1551 initTrigger : function(){
1552 var ts = this.trigger.select('.x-form-trigger', true);
1553 var triggerField = this;
1554 ts.each(function(t, all, index){
1555 var triggerIndex = 'Trigger'+(index+1);
1556 t.hide = function(){
1557 var w = triggerField.wrap.getWidth();
1558 this.dom.style.display = 'none';
1559 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
1560 this['hidden' + triggerIndex] = true;
1562 t.show = function(){
1563 var w = triggerField.wrap.getWidth();
1564 this.dom.style.display = '';
1565 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
1566 this['hidden' + triggerIndex] = false;
1569 if(this['hide'+triggerIndex]){
1570 t.dom.style.display = 'none';
1571 this['hidden' + triggerIndex] = true;
1573 this.mon(t, 'click', this['on'+triggerIndex+'Click'], this, {preventDefault:true});
1574 t.addClassOnOver('x-form-trigger-over');
1575 t.addClassOnClick('x-form-trigger-click');
1577 this.triggers = ts.elements;
1580 getTriggerWidth: function(){
1582 Ext.each(this.triggers, function(t, index){
1583 var triggerIndex = 'Trigger' + (index + 1),
1585 if(w === 0 && !this['hidden' + triggerIndex]){
1586 tw += this.defaultTriggerWidth;
1595 onDestroy : function() {
1596 Ext.destroy(this.triggers);
1597 Ext.form.TwinTriggerField.superclass.onDestroy.call(this);
1601 * The function that should handle the trigger's click event. This method does nothing by default
1602 * until overridden by an implementing function. See {@link Ext.form.TriggerField#onTriggerClick}
1603 * for additional information.
1605 * @param {EventObject} e
1607 onTrigger1Click : Ext.emptyFn,
1609 * The function that should handle the trigger's click event. This method does nothing by default
1610 * until overridden by an implementing function. See {@link Ext.form.TriggerField#onTriggerClick}
1611 * for additional information.
1613 * @param {EventObject} e
1615 onTrigger2Click : Ext.emptyFn
1617 Ext.reg('trigger', Ext.form.TriggerField);
1619 * @class Ext.form.TextArea
1620 * @extends Ext.form.TextField
1621 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
1622 * support for auto-sizing.
1624 * Creates a new TextArea
1625 * @param {Object} config Configuration options
1628 Ext.form.TextArea = Ext.extend(Ext.form.TextField, {
1630 * @cfg {Number} growMin The minimum height to allow when <tt>{@link Ext.form.TextField#grow grow}=true</tt>
1631 * (defaults to <tt>60</tt>)
1635 * @cfg {Number} growMax The maximum height to allow when <tt>{@link Ext.form.TextField#grow grow}=true</tt>
1636 * (defaults to <tt>1000</tt>)
1639 growAppend : ' \n ',
1641 enterIsSpecial : false,
1644 * @cfg {Boolean} preventScrollbars <tt>true</tt> to prevent scrollbars from appearing regardless of how much text is
1645 * in the field. This option is only relevant when {@link #grow} is <tt>true</tt>. Equivalent to setting overflow: hidden, defaults to
1648 preventScrollbars: false,
1650 * @cfg {String/Object} autoCreate <p>A {@link Ext.DomHelper DomHelper} element spec, or true for a default
1651 * element spec. Used to create the {@link Ext.Component#getEl Element} which will encapsulate this Component.
1652 * See <tt>{@link Ext.Component#autoEl autoEl}</tt> for details. Defaults to:</p>
1653 * <pre><code>{tag: "textarea", style: "width:100px;height:60px;", autocomplete: "off"}</code></pre>
1657 onRender : function(ct, position){
1659 this.defaultAutoCreate = {
1661 style:"width:100px;height:60px;",
1665 Ext.form.TextArea.superclass.onRender.call(this, ct, position);
1667 this.textSizeEl = Ext.DomHelper.append(document.body, {
1668 tag: "pre", cls: "x-form-grow-sizer"
1670 if(this.preventScrollbars){
1671 this.el.setStyle("overflow", "hidden");
1673 this.el.setHeight(this.growMin);
1677 onDestroy : function(){
1678 Ext.removeNode(this.textSizeEl);
1679 Ext.form.TextArea.superclass.onDestroy.call(this);
1682 fireKey : function(e){
1683 if(e.isSpecialKey() && (this.enterIsSpecial || (e.getKey() != e.ENTER || e.hasModifier()))){
1684 this.fireEvent("specialkey", this, e);
1689 doAutoSize : function(e){
1690 return !e.isNavKeyPress() || e.getKey() == e.ENTER;
1694 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
1695 * This only takes effect if grow = true, and fires the {@link #autosize} event if the height changes.
1697 autoSize: function(){
1698 if(!this.grow || !this.textSizeEl){
1702 v = Ext.util.Format.htmlEncode(el.dom.value),
1703 ts = this.textSizeEl,
1706 Ext.fly(ts).setWidth(this.el.getWidth());
1710 v += this.growAppend;
1712 v = v.replace(/\n/g, ' <br />');
1716 h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
1717 if(h != this.lastHeight){
1718 this.lastHeight = h;
1719 this.el.setHeight(h);
1720 this.fireEvent("autosize", this, h);
1724 Ext.reg('textarea', Ext.form.TextArea);/**
1725 * @class Ext.form.NumberField
1726 * @extends Ext.form.TextField
1727 * Numeric text field that provides automatic keystroke filtering and numeric validation.
1729 * Creates a new NumberField
1730 * @param {Object} config Configuration options
1731 * @xtype numberfield
1733 Ext.form.NumberField = Ext.extend(Ext.form.TextField, {
1735 * @cfg {RegExp} stripCharsRe @hide
1738 * @cfg {RegExp} maskRe @hide
1741 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
1743 fieldClass: "x-form-field x-form-num-field",
1745 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
1747 allowDecimals : true,
1749 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
1751 decimalSeparator : ".",
1753 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
1755 decimalPrecision : 2,
1757 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
1759 allowNegative : true,
1761 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
1763 minValue : Number.NEGATIVE_INFINITY,
1765 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
1767 maxValue : Number.MAX_VALUE,
1769 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
1771 minText : "The minimum value for this field is {0}",
1773 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
1775 maxText : "The maximum value for this field is {0}",
1777 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
1778 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
1780 nanText : "{0} is not a valid number",
1782 * @cfg {String} baseChars The base set of characters to evaluate as valid numbers (defaults to '0123456789').
1784 baseChars : "0123456789",
1787 initEvents : function(){
1788 var allowed = this.baseChars + '';
1789 if (this.allowDecimals) {
1790 allowed += this.decimalSeparator;
1792 if (this.allowNegative) {
1795 this.maskRe = new RegExp('[' + Ext.escapeRe(allowed) + ']');
1796 Ext.form.NumberField.superclass.initEvents.call(this);
1800 validateValue : function(value){
1801 if(!Ext.form.NumberField.superclass.validateValue.call(this, value)){
1804 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
1807 value = String(value).replace(this.decimalSeparator, ".");
1809 this.markInvalid(String.format(this.nanText, value));
1812 var num = this.parseValue(value);
1813 if(num < this.minValue){
1814 this.markInvalid(String.format(this.minText, this.minValue));
1817 if(num > this.maxValue){
1818 this.markInvalid(String.format(this.maxText, this.maxValue));
1824 getValue : function(){
1825 return this.fixPrecision(this.parseValue(Ext.form.NumberField.superclass.getValue.call(this)));
1828 setValue : function(v){
1829 v = Ext.isNumber(v) ? v : parseFloat(String(v).replace(this.decimalSeparator, "."));
1830 v = isNaN(v) ? '' : String(v).replace(".", this.decimalSeparator);
1831 return Ext.form.NumberField.superclass.setValue.call(this, v);
1835 * Replaces any existing {@link #minValue} with the new value.
1836 * @param {Number} value The minimum value
1838 setMinValue : function(value){
1839 this.minValue = Ext.num(value, Number.NEGATIVE_INFINITY);
1843 * Replaces any existing {@link #maxValue} with the new value.
1844 * @param {Number} value The maximum value
1846 setMaxValue : function(value){
1847 this.maxValue = Ext.num(value, Number.MAX_VALUE);
1851 parseValue : function(value){
1852 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
1853 return isNaN(value) ? '' : value;
1857 fixPrecision : function(value){
1858 var nan = isNaN(value);
1859 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
1860 return nan ? '' : value;
1862 return parseFloat(parseFloat(value).toFixed(this.decimalPrecision));
1865 beforeBlur : function(){
1866 var v = this.parseValue(this.getRawValue());
1867 if(!Ext.isEmpty(v)){
1868 this.setValue(this.fixPrecision(v));
1872 Ext.reg('numberfield', Ext.form.NumberField);/**
1873 * @class Ext.form.DateField
1874 * @extends Ext.form.TriggerField
1875 * Provides a date input field with a {@link Ext.DatePicker} dropdown and automatic date validation.
1877 * Create a new DateField
1878 * @param {Object} config
1881 Ext.form.DateField = Ext.extend(Ext.form.TriggerField, {
1883 * @cfg {String} format
1884 * The default date format string which can be overriden for localization support. The format must be
1885 * valid according to {@link Date#parseDate} (defaults to <tt>'m/d/Y'</tt>).
1889 * @cfg {String} altFormats
1890 * Multiple date formats separated by "<tt>|</tt>" to try when parsing a user input value and it
1891 * does not match the defined format (defaults to
1892 * <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>).
1894 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",
1896 * @cfg {String} disabledDaysText
1897 * The tooltip to display when the date falls on a disabled day (defaults to <tt>'Disabled'</tt>)
1899 disabledDaysText : "Disabled",
1901 * @cfg {String} disabledDatesText
1902 * The tooltip text to display when the date falls on a disabled date (defaults to <tt>'Disabled'</tt>)
1904 disabledDatesText : "Disabled",
1906 * @cfg {String} minText
1907 * The error text to display when the date in the cell is before <tt>{@link #minValue}</tt> (defaults to
1908 * <tt>'The date in this field must be after {minValue}'</tt>).
1910 minText : "The date in this field must be equal to or after {0}",
1912 * @cfg {String} maxText
1913 * The error text to display when the date in the cell is after <tt>{@link #maxValue}</tt> (defaults to
1914 * <tt>'The date in this field must be before {maxValue}'</tt>).
1916 maxText : "The date in this field must be equal to or before {0}",
1918 * @cfg {String} invalidText
1919 * The error text to display when the date in the field is invalid (defaults to
1920 * <tt>'{value} is not a valid date - it must be in the format {format}'</tt>).
1922 invalidText : "{0} is not a valid date - it must be in the format {1}",
1924 * @cfg {String} triggerClass
1925 * An additional CSS class used to style the trigger button. The trigger will always get the
1926 * class <tt>'x-form-trigger'</tt> and <tt>triggerClass</tt> will be <b>appended</b> if specified
1927 * (defaults to <tt>'x-form-date-trigger'</tt> which displays a calendar icon).
1929 triggerClass : 'x-form-date-trigger',
1931 * @cfg {Boolean} showToday
1932 * <tt>false</tt> to hide the footer area of the DatePicker containing the Today button and disable
1933 * the keyboard handler for spacebar that selects the current date (defaults to <tt>true</tt>).
1937 * @cfg {Date/String} minValue
1938 * The minimum allowed date. Can be either a Javascript date object or a string date in a
1939 * valid format (defaults to null).
1942 * @cfg {Date/String} maxValue
1943 * The maximum allowed date. Can be either a Javascript date object or a string date in a
1944 * valid format (defaults to null).
1947 * @cfg {Array} disabledDays
1948 * An array of days to disable, 0 based (defaults to null). Some examples:<pre><code>
1949 // disable Sunday and Saturday:
1950 disabledDays: [0, 6]
1951 // disable weekdays:
1952 disabledDays: [1,2,3,4,5]
1956 * @cfg {Array} disabledDates
1957 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
1958 * expression so they are very powerful. Some examples:<pre><code>
1959 // disable these exact dates:
1960 disabledDates: ["03/08/2003", "09/16/2003"]
1961 // disable these days for every year:
1962 disabledDates: ["03/08", "09/16"]
1963 // only match the beginning (useful if you are using short years):
1964 disabledDates: ["^03/08"]
1965 // disable every day in March 2006:
1966 disabledDates: ["03/../2006"]
1967 // disable every day in every March:
1968 disabledDates: ["^03"]
1970 * Note that the format of the dates included in the array should exactly match the {@link #format} config.
1971 * In order to support regular expressions, if you are using a {@link #format date format} that has "." in
1972 * it, you will have to escape the dot when restricting dates. For example: <tt>["03\\.08\\.03"]</tt>.
1975 * @cfg {String/Object} autoCreate
1976 * A {@link Ext.DomHelper DomHelper element specification object}, or <tt>true</tt> for the default element
1977 * specification object:<pre><code>
1978 * autoCreate: {tag: "input", type: "text", size: "10", autocomplete: "off"}
1983 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
1985 initComponent : function(){
1986 Ext.form.DateField.superclass.initComponent.call(this);
1991 * Fires when a date is selected via the date picker.
1992 * @param {Ext.form.DateField} this
1993 * @param {Date} date The date that was selected
1998 if(Ext.isString(this.minValue)){
1999 this.minValue = this.parseDate(this.minValue);
2001 if(Ext.isString(this.maxValue)){
2002 this.maxValue = this.parseDate(this.maxValue);
2004 this.disabledDatesRE = null;
2005 this.initDisabledDays();
2008 initEvents: function() {
2009 Ext.form.DateField.superclass.initEvents.call(this);
2010 this.keyNav = new Ext.KeyNav(this.el, {
2011 "down": function(e) {
2012 this.onTriggerClick();
2021 initDisabledDays : function(){
2022 if(this.disabledDates){
2023 var dd = this.disabledDates,
2024 len = dd.length - 1,
2027 Ext.each(dd, function(d, i){
2028 re += Ext.isDate(d) ? '^' + Ext.escapeRe(d.dateFormat(this.format)) + '$' : dd[i];
2033 this.disabledDatesRE = new RegExp(re + ')');
2038 * Replaces any existing disabled dates with new values and refreshes the DatePicker.
2039 * @param {Array} disabledDates An array of date strings (see the <tt>{@link #disabledDates}</tt> config
2040 * for details on supported values) used to disable a pattern of dates.
2042 setDisabledDates : function(dd){
2043 this.disabledDates = dd;
2044 this.initDisabledDays();
2046 this.menu.picker.setDisabledDates(this.disabledDatesRE);
2051 * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker.
2052 * @param {Array} disabledDays An array of disabled day indexes. See the <tt>{@link #disabledDays}</tt>
2053 * config for details on supported values.
2055 setDisabledDays : function(dd){
2056 this.disabledDays = dd;
2058 this.menu.picker.setDisabledDays(dd);
2063 * Replaces any existing <tt>{@link #minValue}</tt> with the new value and refreshes the DatePicker.
2064 * @param {Date} value The minimum date that can be selected
2066 setMinValue : function(dt){
2067 this.minValue = (Ext.isString(dt) ? this.parseDate(dt) : dt);
2069 this.menu.picker.setMinDate(this.minValue);
2074 * Replaces any existing <tt>{@link #maxValue}</tt> with the new value and refreshes the DatePicker.
2075 * @param {Date} value The maximum date that can be selected
2077 setMaxValue : function(dt){
2078 this.maxValue = (Ext.isString(dt) ? this.parseDate(dt) : dt);
2080 this.menu.picker.setMaxDate(this.maxValue);
2085 validateValue : function(value){
2086 value = this.formatDate(value);
2087 if(!Ext.form.DateField.superclass.validateValue.call(this, value)){
2090 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
2094 value = this.parseDate(value);
2096 this.markInvalid(String.format(this.invalidText, svalue, this.format));
2099 var time = value.getTime();
2100 if(this.minValue && time < this.minValue.getTime()){
2101 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
2104 if(this.maxValue && time > this.maxValue.getTime()){
2105 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
2108 if(this.disabledDays){
2109 var day = value.getDay();
2110 for(var i = 0; i < this.disabledDays.length; i++) {
2111 if(day === this.disabledDays[i]){
2112 this.markInvalid(this.disabledDaysText);
2117 var fvalue = this.formatDate(value);
2118 if(this.disabledDatesRE && this.disabledDatesRE.test(fvalue)){
2119 this.markInvalid(String.format(this.disabledDatesText, fvalue));
2126 // Provides logic to override the default TriggerField.validateBlur which just returns true
2127 validateBlur : function(){
2128 return !this.menu || !this.menu.isVisible();
2132 * Returns the current date value of the date field.
2133 * @return {Date} The date value
2135 getValue : function(){
2136 return this.parseDate(Ext.form.DateField.superclass.getValue.call(this)) || "";
2140 * Sets the value of the date field. You can pass a date object or any string that can be
2141 * parsed into a valid date, using <tt>{@link #format}</tt> as the date format, according
2142 * to the same rules as {@link Date#parseDate} (the default format used is <tt>"m/d/Y"</tt>).
2145 //All of these calls set the same date value (May 4, 2006)
2147 //Pass a date object:
2148 var dt = new Date('5/4/2006');
2149 dateField.setValue(dt);
2151 //Pass a date string (default format):
2152 dateField.setValue('05/04/2006');
2154 //Pass a date string (custom format):
2155 dateField.format = 'Y-m-d';
2156 dateField.setValue('2006-05-04');
2158 * @param {String/Date} date The date or valid date string
2159 * @return {Ext.form.Field} this
2161 setValue : function(date){
2162 return Ext.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
2166 parseDate : function(value){
2167 if(!value || Ext.isDate(value)){
2170 var v = Date.parseDate(value, this.format);
2171 if(!v && this.altFormats){
2172 if(!this.altFormatsArray){
2173 this.altFormatsArray = this.altFormats.split("|");
2175 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
2176 v = Date.parseDate(value, this.altFormatsArray[i]);
2183 onDestroy : function(){
2184 Ext.destroy(this.menu, this.keyNav);
2185 Ext.form.DateField.superclass.onDestroy.call(this);
2189 formatDate : function(date){
2190 return Ext.isDate(date) ? date.dateFormat(this.format) : date;
2194 * @method onTriggerClick
2198 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
2199 onTriggerClick : function(){
2203 if(this.menu == null){
2204 this.menu = new Ext.menu.DateMenu({
2206 focusOnSelect: false
2210 Ext.apply(this.menu.picker, {
2211 minDate : this.minValue,
2212 maxDate : this.maxValue,
2213 disabledDatesRE : this.disabledDatesRE,
2214 disabledDatesText : this.disabledDatesText,
2215 disabledDays : this.disabledDays,
2216 disabledDaysText : this.disabledDaysText,
2217 format : this.format,
2218 showToday : this.showToday,
2219 minText : String.format(this.minText, this.formatDate(this.minValue)),
2220 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
2222 this.menu.picker.setValue(this.getValue() || new Date());
2223 this.menu.show(this.el, "tl-bl?");
2224 this.menuEvents('on');
2228 menuEvents: function(method){
2229 this.menu[method]('select', this.onSelect, this);
2230 this.menu[method]('hide', this.onMenuHide, this);
2231 this.menu[method]('show', this.onFocus, this);
2234 onSelect: function(m, d){
2236 this.fireEvent('select', this, d);
2240 onMenuHide: function(){
2241 this.focus(false, 60);
2242 this.menuEvents('un');
2246 beforeBlur : function(){
2247 var v = this.parseDate(this.getRawValue());
2254 * @cfg {Boolean} grow @hide
2257 * @cfg {Number} growMin @hide
2260 * @cfg {Number} growMax @hide
2267 Ext.reg('datefield', Ext.form.DateField);/**
\r
2268 * @class Ext.form.DisplayField
\r
2269 * @extends Ext.form.Field
\r
2270 * A display-only text field which is not validated and not submitted.
\r
2272 * Creates a new DisplayField.
\r
2273 * @param {Object} config Configuration options
\r
2274 * @xtype displayfield
\r
2276 Ext.form.DisplayField = Ext.extend(Ext.form.Field, {
\r
2277 validationEvent : false,
\r
2278 validateOnBlur : false,
\r
2279 defaultAutoCreate : {tag: "div"},
\r
2281 * @cfg {String} fieldClass The default CSS class for the field (defaults to <tt>"x-form-display-field"</tt>)
\r
2283 fieldClass : "x-form-display-field",
\r
2285 * @cfg {Boolean} htmlEncode <tt>false</tt> to skip HTML-encoding the text when rendering it (defaults to
\r
2286 * <tt>false</tt>). This might be useful if you want to include tags in the field's innerHTML rather than
\r
2287 * rendering them as string literals per the default logic.
\r
2289 htmlEncode: false,
\r
2292 initEvents : Ext.emptyFn,
\r
2294 isValid : function(){
\r
2298 validate : function(){
\r
2302 getRawValue : function(){
\r
2303 var v = this.rendered ? this.el.dom.innerHTML : Ext.value(this.value, '');
\r
2304 if(v === this.emptyText){
\r
2307 if(this.htmlEncode){
\r
2308 v = Ext.util.Format.htmlDecode(v);
\r
2313 getValue : function(){
\r
2314 return this.getRawValue();
\r
2317 getName: function() {
\r
2321 setRawValue : function(v){
\r
2322 if(this.htmlEncode){
\r
2323 v = Ext.util.Format.htmlEncode(v);
\r
2325 return this.rendered ? (this.el.dom.innerHTML = (Ext.isEmpty(v) ? '' : v)) : (this.value = v);
\r
2328 setValue : function(v){
\r
2329 this.setRawValue(v);
\r
2333 * @cfg {String} inputType
\r
2337 * @cfg {Boolean} disabled
\r
2341 * @cfg {Boolean} readOnly
\r
2345 * @cfg {Boolean} validateOnBlur
\r
2349 * @cfg {Number} validationDelay
\r
2353 * @cfg {String/Boolean} validationEvent
\r
2358 Ext.reg('displayfield', Ext.form.DisplayField);
\r
2360 * @class Ext.form.ComboBox
2361 * @extends Ext.form.TriggerField
2362 * <p>A combobox control with support for autocomplete, remote-loading, paging and many other features.</p>
2363 * <p>A ComboBox works in a similar manner to a traditional HTML <select> field. The difference is
2364 * that to submit the {@link #valueField}, you must specify a {@link #hiddenName} to create a hidden input
2365 * field to hold the value of the valueField. The <i>{@link #displayField}</i> is shown in the text field
2366 * which is named according to the {@link #name}.</p>
2367 * <p><b><u>Events</u></b></p>
2368 * <p>To do something when something in ComboBox is selected, configure the select event:<pre><code>
2369 var cb = new Ext.form.ComboBox({
2370 // all of your config options
2373 'select': yourFunction
2377 // Alternatively, you can assign events after the object is created:
2378 var cb = new Ext.form.ComboBox(yourOptions);
2379 cb.on('select', yourFunction, yourScope);
2382 * <p><b><u>ComboBox in Grid</u></b></p>
2383 * <p>If using a ComboBox in an {@link Ext.grid.EditorGridPanel Editor Grid} a {@link Ext.grid.Column#renderer renderer}
2384 * will be needed to show the displayField when the editor is not active. Set up the renderer manually, or implement
2385 * a reusable render, for example:<pre><code>
2386 // create reusable renderer
2387 Ext.util.Format.comboRenderer = function(combo){
2388 return function(value){
2389 var record = combo.findRecord(combo.{@link #valueField}, value);
2390 return record ? record.get(combo.{@link #displayField}) : combo.{@link #valueNotFoundText};
2394 // create the combo instance
2395 var combo = new Ext.form.ComboBox({
2396 {@link #typeAhead}: true,
2397 {@link #triggerAction}: 'all',
2398 {@link #lazyRender}:true,
2399 {@link #mode}: 'local',
2400 {@link #store}: new Ext.data.ArrayStore({
2406 data: [[1, 'item1'], [2, 'item2']]
2408 {@link #valueField}: 'myId',
2409 {@link #displayField}: 'displayText'
2412 // snippet of column model used within grid
2413 var cm = new Ext.grid.ColumnModel([{
2416 header: "Some Header",
2417 dataIndex: 'whatever',
2419 editor: combo, // specify reference to combo instance
2420 renderer: Ext.util.Format.comboRenderer(combo) // pass combo instance to reusable renderer
2426 * <p><b><u>Filtering</u></b></p>
2427 * <p>A ComboBox {@link #doQuery uses filtering itself}, for information about filtering the ComboBox
2428 * store manually see <tt>{@link #lastQuery}</tt>.</p>
2430 * Create a new ComboBox.
2431 * @param {Object} config Configuration options
2434 Ext.form.ComboBox = Ext.extend(Ext.form.TriggerField, {
2436 * @cfg {Mixed} transform The id, DOM node or element of an existing HTML SELECT to convert to a ComboBox.
2437 * Note that if you specify this and the combo is going to be in an {@link Ext.form.BasicForm} or
2438 * {@link Ext.form.FormPanel}, you must also set <tt>{@link #lazyRender} = true</tt>.
2441 * @cfg {Boolean} lazyRender <tt>true</tt> to prevent the ComboBox from rendering until requested
2442 * (should always be used when rendering into an {@link Ext.Editor} (e.g. {@link Ext.grid.EditorGridPanel Grids}),
2443 * defaults to <tt>false</tt>).
2446 * @cfg {String/Object} autoCreate <p>A {@link Ext.DomHelper DomHelper} element spec, or <tt>true</tt> for a default
2447 * element spec. Used to create the {@link Ext.Component#getEl Element} which will encapsulate this Component.
2448 * See <tt>{@link Ext.Component#autoEl autoEl}</tt> for details. Defaults to:</p>
2449 * <pre><code>{tag: "input", type: "text", size: "24", autocomplete: "off"}</code></pre>
2452 * @cfg {Ext.data.Store/Array} store The data source to which this combo is bound (defaults to <tt>undefined</tt>).
2453 * Acceptable values for this property are:
2454 * <div class="mdetail-params"><ul>
2455 * <li><b>any {@link Ext.data.Store Store} subclass</b></li>
2456 * <li><b>an Array</b> : Arrays will be converted to a {@link Ext.data.ArrayStore} internally,
2457 * automatically generating {@link Ext.data.Field#name field names} to work with all data components.
2458 * <div class="mdetail-params"><ul>
2459 * <li><b>1-dimensional array</b> : (e.g., <tt>['Foo','Bar']</tt>)<div class="sub-desc">
2460 * A 1-dimensional array will automatically be expanded (each array item will be used for both the combo
2461 * {@link #valueField} and {@link #displayField})</div></li>
2462 * <li><b>2-dimensional array</b> : (e.g., <tt>[['f','Foo'],['b','Bar']]</tt>)<div class="sub-desc">
2463 * For a multi-dimensional array, the value in index 0 of each item will be assumed to be the combo
2464 * {@link #valueField}, while the value at index 1 is assumed to be the combo {@link #displayField}.
2465 * </div></li></ul></div></li></ul></div>
2466 * <p>See also <tt>{@link #mode}</tt>.</p>
2469 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
2470 * the dropdown list (defaults to undefined, with no header element)
2474 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
2476 * @cfg {Number} listWidth The width (used as a parameter to {@link Ext.Element#setWidth}) of the dropdown
2477 * list (defaults to the width of the ComboBox field). See also <tt>{@link #minListWidth}
2480 * @cfg {String} displayField The underlying {@link Ext.data.Field#name data field name} to bind to this
2481 * ComboBox (defaults to undefined if <tt>{@link #mode} = 'remote'</tt> or <tt>'field1'</tt> if
2482 * {@link #transform transforming a select} or if the {@link #store field name is autogenerated based on
2483 * the store configuration}).
2484 * <p>See also <tt>{@link #valueField}</tt>.</p>
2485 * <p><b>Note</b>: if using a ComboBox in an {@link Ext.grid.EditorGridPanel Editor Grid} a
2486 * {@link Ext.grid.Column#renderer renderer} will be needed to show the displayField when the editor is not
2490 * @cfg {String} valueField The underlying {@link Ext.data.Field#name data value name} to bind to this
2491 * ComboBox (defaults to undefined if <tt>{@link #mode} = 'remote'</tt> or <tt>'field2'</tt> if
2492 * {@link #transform transforming a select} or if the {@link #store field name is autogenerated based on
2493 * the store configuration}).
2494 * <p><b>Note</b>: use of a <tt>valueField</tt> requires the user to make a selection in order for a value to be
2495 * mapped. See also <tt>{@link #hiddenName}</tt>, <tt>{@link #hiddenValue}</tt>, and <tt>{@link #displayField}</tt>.</p>
2498 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
2499 * field's data value (defaults to the underlying DOM element's name). Required for the combo's value to automatically
2500 * post during a form submission. See also {@link #valueField}.
2501 * <p><b>Note</b>: the hidden field's id will also default to this name if {@link #hiddenId} is not specified.
2502 * The ComboBox {@link Ext.Component#id id} and the <tt>{@link #hiddenId}</tt> <b>should be different</b>, since
2503 * no two DOM nodes should share the same id. So, if the ComboBox <tt>{@link Ext.form.Field#name name}</tt> and
2504 * <tt>hiddenName</tt> are the same, you should specify a unique <tt>{@link #hiddenId}</tt>.</p>
2507 * @cfg {String} hiddenId If <tt>{@link #hiddenName}</tt> is specified, <tt>hiddenId</tt> can also be provided
2508 * to give the hidden field a unique id (defaults to the <tt>{@link #hiddenName}</tt>). The <tt>hiddenId</tt>
2509 * and combo {@link Ext.Component#id id} should be different, since no two DOM
2510 * nodes should share the same id.
2513 * @cfg {String} hiddenValue Sets the initial value of the hidden field if {@link #hiddenName} is
2514 * specified to contain the selected {@link #valueField}, from the Store. Defaults to the configured
2515 * <tt>{@link Ext.form.Field#value value}</tt>.
2518 * @cfg {String} listClass The CSS class to add to the predefined <tt>'x-combo-list'</tt> class
2519 * applied the dropdown list element (defaults to '').
2523 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list
2524 * (defaults to <tt>'x-combo-selected'</tt>)
2526 selectedClass : 'x-combo-selected',
2528 * @cfg {String} listEmptyText The empty text to display in the data view if no items are found.
2533 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always
2534 * get the class <tt>'x-form-trigger'</tt> and <tt>triggerClass</tt> will be <b>appended</b> if specified
2535 * (defaults to <tt>'x-form-arrow-trigger'</tt> which displays a downward arrow icon).
2537 triggerClass : 'x-form-arrow-trigger',
2539 * @cfg {Boolean/String} shadow <tt>true</tt> or <tt>"sides"</tt> for the default effect, <tt>"frame"</tt> for
2540 * 4-way shadow, and <tt>"drop"</tt> for bottom-right
2544 * @cfg {String/Array} listAlign A valid anchor position value. See <tt>{@link Ext.Element#alignTo}</tt> for details
2545 * on supported anchor positions and offsets. To specify x/y offsets as well, this value
2546 * may be specified as an Array of <tt>{@link Ext.Element#alignTo}</tt> method arguments.</p>
2547 * <pre><code>[ 'tl-bl?', [6,0] ]</code></pre>(defaults to <tt>'tl-bl?'</tt>)
2549 listAlign : 'tl-bl?',
2551 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown
2552 * (defaults to <tt>300</tt>)
2556 * @cfg {Number} minHeight The minimum height in pixels of the dropdown list when the list is constrained by its
2557 * distance to the viewport edges (defaults to <tt>90</tt>)
2561 * @cfg {String} triggerAction The action to execute when the trigger is clicked.
2562 * <div class="mdetail-params"><ul>
2563 * <li><b><tt>'query'</tt></b> : <b>Default</b>
2564 * <p class="sub-desc">{@link #doQuery run the query} using the {@link Ext.form.Field#getRawValue raw value}.</p></li>
2565 * <li><b><tt>'all'</tt></b> :
2566 * <p class="sub-desc">{@link #doQuery run the query} specified by the <tt>{@link #allQuery}</tt> config option</p></li>
2568 * <p>See also <code>{@link #queryParam}</code>.</p>
2570 triggerAction : 'query',
2572 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and
2573 * {@link #typeAhead} activate (defaults to <tt>4</tt> if <tt>{@link #mode} = 'remote'</tt> or <tt>0</tt> if
2574 * <tt>{@link #mode} = 'local'</tt>, does not apply if
2575 * <tt>{@link Ext.form.TriggerField#editable editable} = false</tt>).
2579 * @cfg {Boolean} autoSelect <tt>true</tt> to select the first result gathered by the data store (defaults
2580 * to <tt>true</tt>). A false value would require a manual selection from the dropdown list to set the components value
2581 * unless the value of ({@link #typeAheadDelay}) were true.
2585 * @cfg {Boolean} typeAhead <tt>true</tt> to populate and autoselect the remainder of the text being
2586 * typed after a configurable delay ({@link #typeAheadDelay}) if it matches a known value (defaults
2587 * to <tt>false</tt>)
2591 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and
2592 * sending the query to filter the dropdown list (defaults to <tt>500</tt> if <tt>{@link #mode} = 'remote'</tt>
2593 * or <tt>10</tt> if <tt>{@link #mode} = 'local'</tt>)
2597 * @cfg {Number} pageSize If greater than <tt>0</tt>, a {@link Ext.PagingToolbar} is displayed in the
2598 * footer of the dropdown list and the {@link #doQuery filter queries} will execute with page start and
2599 * {@link Ext.PagingToolbar#pageSize limit} parameters. Only applies when <tt>{@link #mode} = 'remote'</tt>
2600 * (defaults to <tt>0</tt>).
2604 * @cfg {Boolean} selectOnFocus <tt>true</tt> to select any existing text in the field immediately on focus.
2605 * Only applies when <tt>{@link Ext.form.TriggerField#editable editable} = true</tt> (defaults to
2608 selectOnFocus : false,
2610 * @cfg {String} queryParam Name of the query ({@link Ext.data.Store#baseParam baseParam} name for the store)
2611 * as it will be passed on the querystring (defaults to <tt>'query'</tt>)
2613 queryParam : 'query',
2615 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
2616 * when <tt>{@link #mode} = 'remote'</tt> (defaults to <tt>'Loading...'</tt>)
2618 loadingText : 'Loading...',
2620 * @cfg {Boolean} resizable <tt>true</tt> to add a resize handle to the bottom of the dropdown list
2621 * (creates an {@link Ext.Resizable} with 'se' {@link Ext.Resizable#pinned pinned} handles).
2622 * Defaults to <tt>false</tt>.
2626 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if
2627 * <tt>{@link #resizable} = true</tt> (defaults to <tt>8</tt>)
2631 * @cfg {String} allQuery The text query to send to the server to return all records for the list
2632 * with no filtering (defaults to '')
2636 * @cfg {String} mode Acceptable values are:
2637 * <div class="mdetail-params"><ul>
2638 * <li><b><tt>'remote'</tt></b> : <b>Default</b>
2639 * <p class="sub-desc">Automatically loads the <tt>{@link #store}</tt> the <b>first</b> time the trigger
2640 * is clicked. If you do not want the store to be automatically loaded the first time the trigger is
2641 * clicked, set to <tt>'local'</tt> and manually load the store. To force a requery of the store
2642 * <b>every</b> time the trigger is clicked see <tt>{@link #lastQuery}</tt>.</p></li>
2643 * <li><b><tt>'local'</tt></b> :
2644 * <p class="sub-desc">ComboBox loads local data</p>
2646 var combo = new Ext.form.ComboBox({
2647 renderTo: document.body,
2649 store: new Ext.data.ArrayStore({
2652 'myId', // numeric value is the key
2655 data: [[1, 'item1'], [2, 'item2']] // data is local
2658 displayField: 'displayText',
2659 triggerAction: 'all'
2661 * </code></pre></li>
2666 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to <tt>70</tt>, will
2667 * be ignored if <tt>{@link #listWidth}</tt> has a higher value)
2671 * @cfg {Boolean} forceSelection <tt>true</tt> to restrict the selected value to one of the values in the list,
2672 * <tt>false</tt> to allow the user to set arbitrary text into the field (defaults to <tt>false</tt>)
2674 forceSelection : false,
2676 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
2677 * if <tt>{@link #typeAhead} = true</tt> (defaults to <tt>250</tt>)
2679 typeAheadDelay : 250,
2681 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
2682 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined). If this
2683 * default text is used, it means there is no value set and no validation will occur on this field.
2687 * @cfg {Boolean} lazyInit <tt>true</tt> to not initialize the list for this combo until the field is focused
2688 * (defaults to <tt>true</tt>)
2693 * @cfg {Boolean} clearFilterOnReset <tt>true</tt> to clear any filters on the store (when in local mode) when reset is called
2694 * (defaults to <tt>true</tt>)
2696 clearFilterOnReset : true,
2699 * @cfg {Boolean} submitValue False to clear the name attribute on the field so that it is not submitted during a form post.
2700 * If a hiddenName is specified, setting this to true will cause both the hidden field and the element to be submitted.
2701 * Defaults to <tt>undefined</tt>.
2703 submitValue: undefined,
2706 * The value of the match string used to filter the store. Delete this property to force a requery.
2709 var combo = new Ext.form.ComboBox({
2714 // delete the previous query in the beforequery event or set
2715 // combo.lastQuery = null (this will reload the store the next time it expands)
2716 beforequery: function(qe){
2717 delete qe.combo.lastQuery;
2722 * To make sure the filter in the store is not cleared the first time the ComboBox trigger is used
2723 * configure the combo with <tt>lastQuery=''</tt>. Example use:
2725 var combo = new Ext.form.ComboBox({
2728 triggerAction: 'all',
2732 * @property lastQuery
2737 initComponent : function(){
2738 Ext.form.ComboBox.superclass.initComponent.call(this);
2742 * Fires when the dropdown list is expanded
2743 * @param {Ext.form.ComboBox} combo This combo box
2748 * Fires when the dropdown list is collapsed
2749 * @param {Ext.form.ComboBox} combo This combo box
2754 * @event beforeselect
2755 * Fires before a list item is selected. Return false to cancel the selection.
2756 * @param {Ext.form.ComboBox} combo This combo box
2757 * @param {Ext.data.Record} record The data record returned from the underlying store
2758 * @param {Number} index The index of the selected item in the dropdown list
2763 * Fires when a list item is selected
2764 * @param {Ext.form.ComboBox} combo This combo box
2765 * @param {Ext.data.Record} record The data record returned from the underlying store
2766 * @param {Number} index The index of the selected item in the dropdown list
2770 * @event beforequery
2771 * Fires before all queries are processed. Return false to cancel the query or set the queryEvent's
2772 * cancel property to true.
2773 * @param {Object} queryEvent An object that has these properties:<ul>
2774 * <li><code>combo</code> : Ext.form.ComboBox <div class="sub-desc">This combo box</div></li>
2775 * <li><code>query</code> : String <div class="sub-desc">The query</div></li>
2776 * <li><code>forceAll</code> : Boolean <div class="sub-desc">True to force "all" query</div></li>
2777 * <li><code>cancel</code> : Boolean <div class="sub-desc">Set to true to cancel the query</div></li>
2783 var s = Ext.getDom(this.transform);
2784 if(!this.hiddenName){
2785 this.hiddenName = s.name;
2788 this.mode = 'local';
2789 var d = [], opts = s.options;
2790 for(var i = 0, len = opts.length;i < len; i++){
2792 value = (o.hasAttribute ? o.hasAttribute('value') : o.getAttributeNode('value').specified) ? o.value : o.text;
2793 if(o.selected && Ext.isEmpty(this.value, true)) {
2796 d.push([value, o.text]);
2798 this.store = new Ext.data.ArrayStore({
2800 fields: ['value', 'text'],
2804 this.valueField = 'value';
2805 this.displayField = 'text';
2807 s.name = Ext.id(); // wipe out the name in case somewhere else they have a reference
2808 if(!this.lazyRender){
2810 this.el = Ext.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
2811 this.render(this.el.parentNode, s);
2815 //auto-configure store from local array data
2816 else if(this.store){
2817 this.store = Ext.StoreMgr.lookup(this.store);
2818 if(this.store.autoCreated){
2819 this.displayField = this.valueField = 'field1';
2820 if(!this.store.expandData){
2821 this.displayField = 'field2';
2823 this.mode = 'local';
2827 this.selectedIndex = -1;
2828 if(this.mode == 'local'){
2829 if(!Ext.isDefined(this.initialConfig.queryDelay)){
2830 this.queryDelay = 10;
2832 if(!Ext.isDefined(this.initialConfig.minChars)){
2839 onRender : function(ct, position){
2840 if(this.hiddenName && !Ext.isDefined(this.submitValue)){
2841 this.submitValue = false;
2843 Ext.form.ComboBox.superclass.onRender.call(this, ct, position);
2844 if(this.hiddenName){
2845 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName,
2846 id: (this.hiddenId||this.hiddenName)}, 'before', true);
2850 this.el.dom.setAttribute('autocomplete', 'off');
2856 this.on('focus', this.initList, this, {single: true});
2861 initValue : function(){
2862 Ext.form.ComboBox.superclass.initValue.call(this);
2863 if(this.hiddenField){
2864 this.hiddenField.value =
2865 Ext.value(Ext.isDefined(this.hiddenValue) ? this.hiddenValue : this.value, '');
2870 initList : function(){
2872 var cls = 'x-combo-list',
2873 listParent = Ext.getDom(this.getListParent() || Ext.getBody()),
2874 zindex = parseInt(Ext.fly(listParent).getStyle('z-index') ,10);
2876 if (this.ownerCt && !zindex){
2877 this.findParentBy(function(ct){
2878 zindex = parseInt(ct.getPositionEl().getStyle('z-index'), 10);
2883 this.list = new Ext.Layer({
2884 parentEl: listParent,
2885 shadow: this.shadow,
2886 cls: [cls, this.listClass].join(' '),
2888 zindex: (zindex || 12000) + 5
2891 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
2892 this.list.setSize(lw, 0);
2893 this.list.swallowEvent('mousewheel');
2894 this.assetHeight = 0;
2895 if(this.syncFont !== false){
2896 this.list.setStyle('font-size', this.el.getStyle('font-size'));
2899 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
2900 this.assetHeight += this.header.getHeight();
2903 this.innerList = this.list.createChild({cls:cls+'-inner'});
2904 this.mon(this.innerList, 'mouseover', this.onViewOver, this);
2905 this.mon(this.innerList, 'mousemove', this.onViewMove, this);
2906 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
2909 this.footer = this.list.createChild({cls:cls+'-ft'});
2910 this.pageTb = new Ext.PagingToolbar({
2912 pageSize: this.pageSize,
2913 renderTo:this.footer
2915 this.assetHeight += this.footer.getHeight();
2920 * @cfg {String/Ext.XTemplate} tpl <p>The template string, or {@link Ext.XTemplate} instance to
2921 * use to display each item in the dropdown list. The dropdown list is displayed in a
2922 * DataView. See {@link #view}.</p>
2923 * <p>The default template string is:</p><pre><code>
2924 '<tpl for="."><div class="x-combo-list-item">{' + this.displayField + '}</div></tpl>'
2926 * <p>Override the default value to create custom UI layouts for items in the list.
2927 * For example:</p><pre><code>
2928 '<tpl for="."><div ext:qtip="{state}. {nick}" class="x-combo-list-item">{state}</div></tpl>'
2930 * <p>The template <b>must</b> contain one or more substitution parameters using field
2931 * names from the Combo's</b> {@link #store Store}. In the example above an
2932 * <pre>ext:qtip</pre> attribute is added to display other fields from the Store.</p>
2933 * <p>To preserve the default visual look of list items, add the CSS class name
2934 * <pre>x-combo-list-item</pre> to the template's container element.</p>
2935 * <p>Also see {@link #itemSelector} for additional details.</p>
2937 this.tpl = '<tpl for="."><div class="'+cls+'-item">{' + this.displayField + '}</div></tpl>';
2939 * @cfg {String} itemSelector
2940 * <p>A simple CSS selector (e.g. div.some-class or span:first-child) that will be
2941 * used to determine what nodes the {@link #view Ext.DataView} which handles the dropdown
2942 * display will be working with.</p>
2943 * <p><b>Note</b>: this setting is <b>required</b> if a custom XTemplate has been
2944 * specified in {@link #tpl} which assigns a class other than <pre>'x-combo-list-item'</pre>
2945 * to dropdown list items</b>
2950 * The {@link Ext.DataView DataView} used to display the ComboBox's options.
2951 * @type Ext.DataView
2953 this.view = new Ext.DataView({
2954 applyTo: this.innerList,
2957 selectedClass: this.selectedClass,
2958 itemSelector: this.itemSelector || '.' + cls + '-item',
2959 emptyText: this.listEmptyText,
2960 deferEmptyText: false
2963 this.mon(this.view, {
2964 containerclick : this.onViewClick,
2965 click : this.onViewClick,
2969 this.bindStore(this.store, true);
2972 this.resizer = new Ext.Resizable(this.list, {
2973 pinned:true, handles:'se'
2975 this.mon(this.resizer, 'resize', function(r, w, h){
2976 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
2978 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
2979 this.restrictHeight();
2982 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
2988 * <p>Returns the element used to house this ComboBox's pop-up list. Defaults to the document body.</p>
2989 * A custom implementation may be provided as a configuration option if the floating list needs to be rendered
2990 * to a different Element. An example might be rendering the list inside a Menu so that clicking
2991 * the list does not hide the Menu:<pre><code>
2992 var store = new Ext.data.ArrayStore({
2994 fields: ['initials', 'fullname'],
2996 ['FF', 'Fred Flintstone'],
2997 ['BR', 'Barney Rubble']
3001 var combo = new Ext.form.ComboBox({
3003 displayField: 'fullname',
3004 emptyText: 'Select a name...',
3005 forceSelection: true,
3006 getListParent: function() {
3007 return this.el.up('.x-menu');
3009 iconCls: 'no-icon', //use iconCls if placing within menu to shift to right side of menu
3011 selectOnFocus: true,
3012 triggerAction: 'all',
3017 var menu = new Ext.menu.Menu({
3020 combo // A Field in a Menu
3025 getListParent : function() {
3026 return document.body;
3030 * Returns the store associated with this combo.
3031 * @return {Ext.data.Store} The store
3033 getStore : function(){
3038 bindStore : function(store, initial){
3039 if(this.store && !initial){
3040 if(this.store !== store && this.store.autoDestroy){
3041 this.store.destroy();
3043 this.store.un('beforeload', this.onBeforeLoad, this);
3044 this.store.un('load', this.onLoad, this);
3045 this.store.un('exception', this.collapse, this);
3050 this.view.bindStore(null);
3053 this.pageTb.bindStore(null);
3059 this.lastQuery = null;
3061 this.pageTb.bindStore(store);
3065 this.store = Ext.StoreMgr.lookup(store);
3068 beforeload: this.onBeforeLoad,
3070 exception: this.collapse
3074 this.view.bindStore(store);
3080 Ext.form.ComboBox.superclass.reset.call(this);
3081 if(this.clearFilterOnReset && this.mode == 'local'){
3082 this.store.clearFilter();
3087 initEvents : function(){
3088 Ext.form.ComboBox.superclass.initEvents.call(this);
3091 this.keyNav = new Ext.KeyNav(this.el, {
3093 this.inKeyMode = true;
3097 "down" : function(e){
3098 if(!this.isExpanded()){
3099 this.onTriggerClick();
3101 this.inKeyMode = true;
3106 "enter" : function(e){
3110 "esc" : function(e){
3114 "tab" : function(e){
3121 doRelay : function(e, h, hname){
3122 if(hname == 'down' || this.scope.isExpanded()){
3123 // this MUST be called before ComboBox#fireKey()
3124 var relay = Ext.KeyNav.prototype.doRelay.apply(this, arguments);
3125 if(!Ext.isIE && Ext.EventManager.useKeydown){
3126 // call Combo#fireKey() for browsers which use keydown event (except IE)
3127 this.scope.fireKey(e);
3134 forceKeyDown : true,
3135 defaultEventAction: 'stopEvent'
3137 this.queryDelay = Math.max(this.queryDelay || 10,
3138 this.mode == 'local' ? 10 : 250);
3139 this.dqTask = new Ext.util.DelayedTask(this.initQuery, this);
3141 this.taTask = new Ext.util.DelayedTask(this.onTypeAhead, this);
3143 if(!this.enableKeyEvents){
3144 this.mon(this.el, 'keyup', this.onKeyUp, this);
3150 onDestroy : function(){
3152 this.dqTask.cancel();
3155 this.bindStore(null);
3162 Ext.destroyMembers(this, 'hiddenField');
3163 Ext.form.ComboBox.superclass.onDestroy.call(this);
3167 fireKey : function(e){
3168 if (!this.isExpanded()) {
3169 Ext.form.ComboBox.superclass.fireKey.call(this, e);
3174 onResize : function(w, h){
3175 Ext.form.ComboBox.superclass.onResize.apply(this, arguments);
3176 if(this.isVisible() && this.list){
3179 this.bufferSize = w;
3183 doResize: function(w){
3184 if(!Ext.isDefined(this.listWidth)){
3185 var lw = Math.max(w, this.minListWidth);
3186 this.list.setWidth(lw);
3187 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
3192 onEnable : function(){
3193 Ext.form.ComboBox.superclass.onEnable.apply(this, arguments);
3194 if(this.hiddenField){
3195 this.hiddenField.disabled = false;
3200 onDisable : function(){
3201 Ext.form.ComboBox.superclass.onDisable.apply(this, arguments);
3202 if(this.hiddenField){
3203 this.hiddenField.disabled = true;
3208 onBeforeLoad : function(){
3212 this.innerList.update(this.loadingText ?
3213 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
3214 this.restrictHeight();
3215 this.selectedIndex = -1;
3219 onLoad : function(){
3223 if(this.store.getCount() > 0 || this.listEmptyText){
3225 this.restrictHeight();
3226 if(this.lastQuery == this.allQuery){
3228 this.el.dom.select();
3231 if(this.autoSelect !== false && !this.selectByValue(this.value, true)){
3232 this.select(0, true);
3235 if(this.autoSelect !== false){
3238 if(this.typeAhead && this.lastKey != Ext.EventObject.BACKSPACE && this.lastKey != Ext.EventObject.DELETE){
3239 this.taTask.delay(this.typeAheadDelay);
3249 onTypeAhead : function(){
3250 if(this.store.getCount() > 0){
3251 var r = this.store.getAt(0);
3252 var newValue = r.data[this.displayField];
3253 var len = newValue.length;
3254 var selStart = this.getRawValue().length;
3255 if(selStart != len){
3256 this.setRawValue(newValue);
3257 this.selectText(selStart, newValue.length);
3263 assertValue : function(){
3265 var val = this.getRawValue(),
3266 rec = this.findRecord(this.displayField, val);
3268 if(!rec && this.forceSelection){
3269 if(val.length > 0 && val != this.emptyText){
3270 this.el.dom.value = Ext.value(this.lastSelectionText, '');
3271 this.applyEmptyText();
3277 val = rec.get(this.valueField || this.displayField);
3285 onSelect : function(record, index){
3286 if(this.fireEvent('beforeselect', this, record, index) !== false){
3287 this.setValue(record.data[this.valueField || this.displayField]);
3289 this.fireEvent('select', this, record, index);
3294 getName: function(){
3295 var hf = this.hiddenField;
3296 return hf && hf.name ? hf.name : this.hiddenName || Ext.form.ComboBox.superclass.getName.call(this);
3300 * Returns the currently selected field value or empty string if no value is set.
3301 * @return {String} value The selected value
3303 getValue : function(){
3304 if(this.valueField){
3305 return Ext.isDefined(this.value) ? this.value : '';
3307 return Ext.form.ComboBox.superclass.getValue.call(this);
3312 * Clears any text/value currently set in the field
3314 clearValue : function(){
3315 if(this.hiddenField){
3316 this.hiddenField.value = '';
3318 this.setRawValue('');
3319 this.lastSelectionText = '';
3320 this.applyEmptyText();
3325 * Sets the specified value into the field. If the value finds a match, the corresponding record text
3326 * will be displayed in the field. If the value does not match the data value of an existing item,
3327 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
3328 * Otherwise the field will be blank (although the value will still be set).
3329 * @param {String} value The value to match
3330 * @return {Ext.form.Field} this
3332 setValue : function(v){
3334 if(this.valueField){
3335 var r = this.findRecord(this.valueField, v);
3337 text = r.data[this.displayField];
3338 }else if(Ext.isDefined(this.valueNotFoundText)){
3339 text = this.valueNotFoundText;
3342 this.lastSelectionText = text;
3343 if(this.hiddenField){
3344 this.hiddenField.value = Ext.value(v, '');
3346 Ext.form.ComboBox.superclass.setValue.call(this, text);
3352 findRecord : function(prop, value){
3354 if(this.store.getCount() > 0){
3355 this.store.each(function(r){
3356 if(r.data[prop] == value){
3366 onViewMove : function(e, t){
3367 this.inKeyMode = false;
3371 onViewOver : function(e, t){
3372 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
3375 var item = this.view.findItemFromChild(t);
3377 var index = this.view.indexOf(item);
3378 this.select(index, false);
3383 onViewClick : function(doFocus){
3384 var index = this.view.getSelectedIndexes()[0],
3388 this.onSelect(r, index);
3392 if(doFocus !== false){
3399 restrictHeight : function(){
3400 this.innerList.dom.style.height = '';
3401 var inner = this.innerList.dom,
3402 pad = this.list.getFrameWidth('tb') + (this.resizable ? this.handleHeight : 0) + this.assetHeight,
3403 h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight),
3404 ha = this.getPosition()[1]-Ext.getBody().getScroll().top,
3405 hb = Ext.lib.Dom.getViewHeight()-ha-this.getSize().height,
3406 space = Math.max(ha, hb, this.minHeight || 0)-this.list.shadowOffset-pad-5;
3408 h = Math.min(h, space, this.maxHeight);
3410 this.innerList.setHeight(h);
3411 this.list.beginUpdate();
3412 this.list.setHeight(h+pad);
3413 this.list.alignTo.apply(this.list, [this.el].concat(this.listAlign));
3414 this.list.endUpdate();
3418 * Returns true if the dropdown list is expanded, else false.
3420 isExpanded : function(){
3421 return this.list && this.list.isVisible();
3425 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
3426 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
3427 * @param {String} value The data value of the item to select
3428 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
3429 * selected item if it is not currently in view (defaults to true)
3430 * @return {Boolean} True if the value matched an item in the list, else false
3432 selectByValue : function(v, scrollIntoView){
3433 if(!Ext.isEmpty(v, true)){
3434 var r = this.findRecord(this.valueField || this.displayField, v);
3436 this.select(this.store.indexOf(r), scrollIntoView);
3444 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
3445 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
3446 * @param {Number} index The zero-based index of the list item to select
3447 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
3448 * selected item if it is not currently in view (defaults to true)
3450 select : function(index, scrollIntoView){
3451 this.selectedIndex = index;
3452 this.view.select(index);
3453 if(scrollIntoView !== false){
3454 var el = this.view.getNode(index);
3456 this.innerList.scrollChildIntoView(el, false);
3463 selectNext : function(){
3464 var ct = this.store.getCount();
3466 if(this.selectedIndex == -1){
3468 }else if(this.selectedIndex < ct-1){
3469 this.select(this.selectedIndex+1);
3475 selectPrev : function(){
3476 var ct = this.store.getCount();
3478 if(this.selectedIndex == -1){
3480 }else if(this.selectedIndex !== 0){
3481 this.select(this.selectedIndex-1);
3487 onKeyUp : function(e){
3489 if(this.editable !== false && this.readOnly !== true && (k == e.BACKSPACE || !e.isSpecialKey())){
3492 this.dqTask.delay(this.queryDelay);
3494 Ext.form.ComboBox.superclass.onKeyUp.call(this, e);
3498 validateBlur : function(){
3499 return !this.list || !this.list.isVisible();
3503 initQuery : function(){
3504 this.doQuery(this.getRawValue());
3508 beforeBlur : function(){
3513 postBlur : function(){
3514 Ext.form.ComboBox.superclass.postBlur.call(this);
3516 this.inKeyMode = false;
3520 * Execute a query to filter the dropdown list. Fires the {@link #beforequery} event prior to performing the
3521 * query allowing the query action to be canceled if needed.
3522 * @param {String} query The SQL query to execute
3523 * @param {Boolean} forceAll <tt>true</tt> to force the query to execute even if there are currently fewer
3524 * characters in the field than the minimum specified by the <tt>{@link #minChars}</tt> config option. It
3525 * also clears any filter previously saved in the current store (defaults to <tt>false</tt>)
3527 doQuery : function(q, forceAll){
3528 q = Ext.isEmpty(q) ? '' : q;
3535 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
3539 forceAll = qe.forceAll;
3540 if(forceAll === true || (q.length >= this.minChars)){
3541 if(this.lastQuery !== q){
3543 if(this.mode == 'local'){
3544 this.selectedIndex = -1;
3546 this.store.clearFilter();
3548 this.store.filter(this.displayField, q);
3552 this.store.baseParams[this.queryParam] = q;
3554 params: this.getParams(q)
3559 this.selectedIndex = -1;
3566 getParams : function(q){
3568 //p[this.queryParam] = q;
3571 p.limit = this.pageSize;
3577 * Hides the dropdown list if it is currently expanded. Fires the {@link #collapse} event on completion.
3579 collapse : function(){
3580 if(!this.isExpanded()){
3584 Ext.getDoc().un('mousewheel', this.collapseIf, this);
3585 Ext.getDoc().un('mousedown', this.collapseIf, this);
3586 this.fireEvent('collapse', this);
3590 collapseIf : function(e){
3591 if(!e.within(this.wrap) && !e.within(this.list)){
3597 * Expands the dropdown list if it is currently hidden. Fires the {@link #expand} event on completion.
3599 expand : function(){
3600 if(this.isExpanded() || !this.hasFocus){
3603 if(this.bufferSize){
3604 this.doResize(this.bufferSize);
3605 delete this.bufferSize;
3607 this.list.alignTo.apply(this.list, [this.el].concat(this.listAlign));
3610 this.innerList.setOverflow('auto'); // necessary for FF 2.0/Mac
3612 this.mon(Ext.getDoc(), {
3614 mousewheel: this.collapseIf,
3615 mousedown: this.collapseIf
3617 this.fireEvent('expand', this);
3621 * @method onTriggerClick
3625 // Implements the default empty TriggerField.onTriggerClick function
3626 onTriggerClick : function(){
3627 if(this.readOnly || this.disabled){
3630 if(this.isExpanded()){
3635 if(this.triggerAction == 'all') {
3636 this.doQuery(this.allQuery, true);
3638 this.doQuery(this.getRawValue());
3649 * @cfg {Boolean} grow @hide
3652 * @cfg {Number} growMin @hide
3655 * @cfg {Number} growMax @hide
3659 Ext.reg('combo', Ext.form.ComboBox);
3661 * @class Ext.form.Checkbox
3662 * @extends Ext.form.Field
3663 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
3665 * Creates a new Checkbox
3666 * @param {Object} config Configuration options
3669 Ext.form.Checkbox = Ext.extend(Ext.form.Field, {
3671 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
3673 focusClass : undefined,
3675 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to 'x-form-field')
3677 fieldClass : 'x-form-field',
3679 * @cfg {Boolean} checked <tt>true</tt> if the checkbox should render initially checked (defaults to <tt>false</tt>)
3683 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
3684 * {tag: 'input', type: 'checkbox', autocomplete: 'off'})
3686 defaultAutoCreate : { tag: 'input', type: 'checkbox', autocomplete: 'off'},
3688 * @cfg {String} boxLabel The text that appears beside the checkbox
3691 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
3694 * @cfg {Function} handler A function called when the {@link #checked} value changes (can be used instead of
3695 * handling the check event). The handler is passed the following parameters:
3696 * <div class="mdetail-params"><ul>
3697 * <li><b>checkbox</b> : Ext.form.Checkbox<div class="sub-desc">The Checkbox being toggled.</div></li>
3698 * <li><b>checked</b> : Boolean<div class="sub-desc">The new checked state of the checkbox.</div></li>
3702 * @cfg {Object} scope An object to use as the scope ('this' reference) of the {@link #handler} function
3703 * (defaults to this Checkbox).
3707 actionMode : 'wrap',
3710 initComponent : function(){
3711 Ext.form.Checkbox.superclass.initComponent.call(this);
3715 * Fires when the checkbox is checked or unchecked.
3716 * @param {Ext.form.Checkbox} this This checkbox
3717 * @param {Boolean} checked The new checked value
3724 onResize : function(){
3725 Ext.form.Checkbox.superclass.onResize.apply(this, arguments);
3726 if(!this.boxLabel && !this.fieldLabel){
3727 this.el.alignTo(this.wrap, 'c-c');
3732 initEvents : function(){
3733 Ext.form.Checkbox.superclass.initEvents.call(this);
3736 click: this.onClick,
3737 change: this.onClick
3743 * Overridden and disabled. The editor element does not support standard valid/invalid marking.
3746 markInvalid : Ext.emptyFn,
3749 * Overridden and disabled. The editor element does not support standard valid/invalid marking.
3752 clearInvalid : Ext.emptyFn,
3755 onRender : function(ct, position){
3756 Ext.form.Checkbox.superclass.onRender.call(this, ct, position);
3757 if(this.inputValue !== undefined){
3758 this.el.dom.value = this.inputValue;
3760 this.wrap = this.el.wrap({cls: 'x-form-check-wrap'});
3762 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
3765 this.setValue(true);
3767 this.checked = this.el.dom.checked;
3769 // Need to repaint for IE, otherwise positioning is broken
3771 this.wrap.repaint();
3773 this.resizeEl = this.positionEl = this.wrap;
3777 onDestroy : function(){
3778 Ext.destroy(this.wrap);
3779 Ext.form.Checkbox.superclass.onDestroy.call(this);
3783 initValue : function() {
3784 this.originalValue = this.getValue();
3788 * Returns the checked state of the checkbox.
3789 * @return {Boolean} True if checked, else false
3791 getValue : function(){
3793 return this.el.dom.checked;
3795 return this.checked;
3799 onClick : function(){
3800 if(this.el.dom.checked != this.checked){
3801 this.setValue(this.el.dom.checked);
3806 * Sets the checked state of the checkbox, fires the 'check' event, and calls a
3807 * <code>{@link #handler}</code> (if configured).
3808 * @param {Boolean/String} checked The following values will check the checkbox:
3809 * <code>true, 'true', '1', or 'on'</code>. Any other value will uncheck the checkbox.
3810 * @return {Ext.form.Field} this
3812 setValue : function(v){
3813 var checked = this.checked ;
3814 this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
3816 this.el.dom.checked = this.checked;
3817 this.el.dom.defaultChecked = this.checked;
3819 if(checked != this.checked){
3820 this.fireEvent('check', this, this.checked);
3822 this.handler.call(this.scope || this, this, this.checked);
3828 Ext.reg('checkbox', Ext.form.Checkbox);
3830 * @class Ext.form.CheckboxGroup
3831 * @extends Ext.form.Field
3832 * <p>A grouping container for {@link Ext.form.Checkbox} controls.</p>
3833 * <p>Sample usage:</p>
3835 var myCheckboxGroup = new Ext.form.CheckboxGroup({
3837 xtype: 'checkboxgroup',
3838 fieldLabel: 'Single Column',
3839 itemCls: 'x-check-group-alt',
3840 // Put all controls in a single column with width 100%
3843 {boxLabel: 'Item 1', name: 'cb-col-1'},
3844 {boxLabel: 'Item 2', name: 'cb-col-2', checked: true},
3845 {boxLabel: 'Item 3', name: 'cb-col-3'}
3850 * Creates a new CheckboxGroup
3851 * @param {Object} config Configuration options
3852 * @xtype checkboxgroup
3854 Ext.form.CheckboxGroup = Ext.extend(Ext.form.Field, {
3856 * @cfg {Array} items An Array of {@link Ext.form.Checkbox Checkbox}es or Checkbox config objects
3857 * to arrange in the group.
3860 * @cfg {String/Number/Array} columns Specifies the number of columns to use when displaying grouped
3861 * checkbox/radio controls using automatic layout. This config can take several types of values:
3862 * <ul><li><b>'auto'</b> : <p class="sub-desc">The controls will be rendered one per column on one row and the width
3863 * of each column will be evenly distributed based on the width of the overall field container. This is the default.</p></li>
3864 * <li><b>Number</b> : <p class="sub-desc">If you specific a number (e.g., 3) that number of columns will be
3865 * created and the contained controls will be automatically distributed based on the value of {@link #vertical}.</p></li>
3866 * <li><b>Array</b> : Object<p class="sub-desc">You can also specify an array of column widths, mixing integer
3867 * (fixed width) and float (percentage width) values as needed (e.g., [100, .25, .75]). Any integer values will
3868 * be rendered first, then any float values will be calculated as a percentage of the remaining space. Float
3869 * values do not have to add up to 1 (100%) although if you want the controls to take up the entire field
3870 * container you should do so.</p></li></ul>
3874 * @cfg {Boolean} vertical True to distribute contained controls across columns, completely filling each column
3875 * top to bottom before starting on the next column. The number of controls in each column will be automatically
3876 * calculated to keep columns as even as possible. The default value is false, so that controls will be added
3877 * to columns one at a time, completely filling each row left to right before starting on the next row.
3881 * @cfg {Boolean} allowBlank False to validate that at least one item in the group is checked (defaults to true).
3882 * If no items are selected at validation time, {@link @blankText} will be used as the error text.
3886 * @cfg {String} blankText Error text to display if the {@link #allowBlank} validation fails (defaults to "You must
3887 * select at least one item in this group")
3889 blankText : "You must select at least one item in this group",
3892 defaultType : 'checkbox',
3895 groupCls : 'x-form-check-group',
3898 initComponent: function(){
3902 * Fires when the state of a child checkbox changes.
3903 * @param {Ext.form.CheckboxGroup} this
3904 * @param {Array} checked An array containing the checked boxes.
3908 this.on('change', this.validate, this);
3909 Ext.form.CheckboxGroup.superclass.initComponent.call(this);
3913 onRender : function(ct, position){
3922 bufferResize: false // Default this to false, since it doesn't really have a proper ownerCt.
3926 defaultType: this.defaultType,
3934 if(this.items[0].items){
3936 // The container has standard ColumnLayout configs, so pass them in directly
3938 Ext.apply(panelCfg, {
3939 layoutConfig: {columns: this.items.length},
3940 defaults: this.defaults,
3943 for(var i=0, len=this.items.length; i<len; i++){
3944 Ext.applyIf(this.items[i], colCfg);
3949 // The container has field item configs, so we have to generate the column
3950 // panels first then move the items into the columns as needed.
3952 var numCols, cols = [];
3954 if(typeof this.columns == 'string'){ // 'auto' so create a col per item
3955 this.columns = this.items.length;
3957 if(!Ext.isArray(this.columns)){
3959 for(var i=0; i<this.columns; i++){
3960 cs.push((100/this.columns)*.01); // distribute by even %
3965 numCols = this.columns.length;
3967 // Generate the column configs with the correct width setting
3968 for(var i=0; i<numCols; i++){
3969 var cc = Ext.apply({items:[]}, colCfg);
3970 cc[this.columns[i] <= 1 ? 'columnWidth' : 'width'] = this.columns[i];
3972 cc.defaults = Ext.apply(cc.defaults || {}, this.defaults)
3977 // Distribute the original items into the columns
3979 var rows = Math.ceil(this.items.length / numCols), ri = 0;
3980 for(var i=0, len=this.items.length; i<len; i++){
3981 if(i>0 && i%rows==0){
3984 if(this.items[i].fieldLabel){
3985 this.items[i].hideLabel = false;
3987 cols[ri].items.push(this.items[i]);
3990 for(var i=0, len=this.items.length; i<len; i++){
3991 var ci = i % numCols;
3992 if(this.items[i].fieldLabel){
3993 this.items[i].hideLabel = false;
3995 cols[ci].items.push(this.items[i]);
3999 Ext.apply(panelCfg, {
4000 layoutConfig: {columns: numCols},
4005 this.panel = new Ext.Container(panelCfg);
4006 this.panel.ownerCt = this;
4007 this.el = this.panel.getEl();
4009 if(this.forId && this.itemCls){
4010 var l = this.el.up(this.itemCls).child('label', true);
4012 l.setAttribute('htmlFor', this.forId);
4016 var fields = this.panel.findBy(function(c){
4017 return c.isFormField;
4020 this.items = new Ext.util.MixedCollection();
4021 this.items.addAll(fields);
4023 Ext.form.CheckboxGroup.superclass.onRender.call(this, ct, position);
4026 initValue : function(){
4028 this.setValue.apply(this, this.buffered ? this.value : [this.value]);
4029 delete this.buffered;
4034 afterRender : function(){
4035 Ext.form.CheckboxGroup.superclass.afterRender.call(this);
4036 this.eachItem(function(item){
4037 item.on('check', this.fireChecked, this);
4038 item.inGroup = true;
4043 doLayout: function(){
4044 //ugly method required to layout hidden items
4046 this.panel.forceLayout = this.ownerCt.forceLayout;
4047 this.panel.doLayout();
4052 fireChecked: function(){
4054 this.eachItem(function(item){
4059 this.fireEvent('change', this, arr);
4063 validateValue : function(value){
4064 if(!this.allowBlank){
4066 this.eachItem(function(f){
4068 return (blank = false);
4072 this.markInvalid(this.blankText);
4080 isDirty: function(){
4081 //override the behaviour to check sub items.
4082 if (this.disabled || !this.rendered) {
4087 this.eachItem(function(item){
4097 onDisable : function(){
4098 this.eachItem(function(item){
4104 onEnable : function(){
4105 this.eachItem(function(item){
4111 doLayout: function(){
4113 this.panel.forceLayout = this.ownerCt.forceLayout;
4114 this.panel.doLayout();
4119 onResize : function(w, h){
4120 this.panel.setSize(w, h);
4121 this.panel.doLayout();
4124 // inherit docs from Field
4126 this.eachItem(function(c){
4131 // Defer the clearInvalid so if BaseForm's collection is being iterated it will be called AFTER it is complete.
4132 // Important because reset is being called on both the group and the individual items.
4134 this.clearInvalid();
4139 * {@link Ext.form.Checkbox#setValue Set the value(s)} of an item or items
4140 * in the group. Examples illustrating how this method may be called:
4142 // call with name and value
4143 myCheckboxGroup.setValue('cb-col-1', true);
4144 // call with an array of boolean values
4145 myCheckboxGroup.setValue([true, false, false]);
4146 // call with an object literal specifying item:value pairs
4147 myCheckboxGroup.setValue({
4151 // use comma separated string to set items with name to true (checked)
4152 myCheckboxGroup.setValue('cb-col-1,cb-col-3');
4154 * See {@link Ext.form.Checkbox#setValue} for additional information.
4155 * @param {Mixed} id The checkbox to check, or as described by example shown.
4156 * @param {Boolean} value (optional) The value to set the item.
4157 * @return {Ext.form.CheckboxGroup} this
4159 setValue: function(){
4161 this.onSetValue.apply(this, arguments);
4163 this.buffered = true;
4164 this.value = arguments;
4169 onSetValue: function(id, value){
4170 if(arguments.length == 1){
4171 if(Ext.isArray(id)){
4172 // an array of boolean values
4173 Ext.each(id, function(val, idx){
4174 var item = this.items.itemAt(idx);
4179 }else if(Ext.isObject(id)){
4180 // set of name/value pairs
4182 var f = this.getBox(i);
4188 this.setValueForItem(id);
4191 var f = this.getBox(id);
4199 beforeDestroy: function(){
4200 Ext.destroy(this.panel);
4201 Ext.form.CheckboxGroup.superclass.beforeDestroy.call(this);
4205 setValueForItem : function(val){
4206 val = String(val).split(',');
4207 this.eachItem(function(item){
4208 if(val.indexOf(item.inputValue)> -1){
4209 item.setValue(true);
4215 getBox : function(id){
4217 this.eachItem(function(f){
4218 if(id == f || f.dataIndex == id || f.id == id || f.getName() == id){
4227 * Gets an array of the selected {@link Ext.form.Checkbox} in the group.
4228 * @return {Array} An array of the selected checkboxes.
4230 getValue : function(){
4232 this.eachItem(function(item){
4241 eachItem: function(fn){
4242 if(this.items && this.items.each){
4243 this.items.each(fn, this);
4248 * @cfg {String} name
4253 * @method getRawValue
4256 getRawValue : Ext.emptyFn,
4259 * @method setRawValue
4262 setRawValue : Ext.emptyFn
4266 Ext.reg('checkboxgroup', Ext.form.CheckboxGroup);
4268 * @class Ext.form.Radio
4269 * @extends Ext.form.Checkbox
4270 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
4271 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
4273 * Creates a new Radio
4274 * @param {Object} config Configuration options
4277 Ext.form.Radio = Ext.extend(Ext.form.Checkbox, {
4281 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
4284 markInvalid : Ext.emptyFn,
4286 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
4289 clearInvalid : Ext.emptyFn,
4292 * If this radio is part of a group, it will return the selected value
4295 getGroupValue : function(){
4296 var p = this.el.up('form') || Ext.getBody();
4297 var c = p.child('input[name='+this.el.dom.name+']:checked', true);
4298 return c ? c.value : null;
4302 onClick : function(){
4303 if(this.el.dom.checked != this.checked){
4304 var els = this.getCheckEl().select('input[name=' + this.el.dom.name + ']');
4305 els.each(function(el){
4306 if(el.dom.id == this.id){
4307 this.setValue(true);
4309 Ext.getCmp(el.dom.id).setValue(false);
4316 * Sets either the checked/unchecked status of this Radio, or, if a string value
4317 * is passed, checks a sibling Radio of the same name whose value is the value specified.
4318 * @param value {String/Boolean} Checked value, or the value of the sibling radio button to check.
4319 * @return {Ext.form.Field} this
4321 setValue : function(v){
4322 if (typeof v == 'boolean') {
4323 Ext.form.Radio.superclass.setValue.call(this, v);
4324 } else if (this.rendered) {
4325 var r = this.getCheckEl().child('input[name=' + this.el.dom.name + '][value=' + v + ']', true);
4327 Ext.getCmp(r.id).setValue(true);
4334 getCheckEl: function(){
4336 return this.el.up('.x-form-radio-group')
4338 return this.el.up('form') || Ext.getBody();
4341 Ext.reg('radio', Ext.form.Radio);
4343 * @class Ext.form.RadioGroup
4344 * @extends Ext.form.CheckboxGroup
4345 * A grouping container for {@link Ext.form.Radio} controls.
4347 * Creates a new RadioGroup
4348 * @param {Object} config Configuration options
4351 Ext.form.RadioGroup = Ext.extend(Ext.form.CheckboxGroup, {
4353 * @cfg {Array} items An Array of {@link Ext.form.Radio Radio}s or Radio config objects
4354 * to arrange in the group.
4357 * @cfg {Boolean} allowBlank True to allow every item in the group to be blank (defaults to true).
4358 * If allowBlank = false and no items are selected at validation time, {@link @blankText} will
4359 * be used as the error text.
4363 * @cfg {String} blankText Error text to display if the {@link #allowBlank} validation fails
4364 * (defaults to 'You must select one item in this group')
4366 blankText : 'You must select one item in this group',
4369 defaultType : 'radio',
4372 groupCls : 'x-form-radio-group',
4376 * Fires when the state of a child radio changes.
4377 * @param {Ext.form.RadioGroup} this
4378 * @param {Ext.form.Radio} checked The checked radio
4382 * Gets the selected {@link Ext.form.Radio} in the group, if it exists.
4383 * @return {Ext.form.Radio} The selected radio.
4385 getValue : function(){
4387 this.eachItem(function(item){
4397 * Sets the checked radio in the group.
4398 * @param {String/Ext.form.Radio} id The radio to check.
4399 * @param {Boolean} value The value to set the radio.
4400 * @return {Ext.form.RadioGroup} this
4402 onSetValue : function(id, value){
4403 if(arguments.length > 1){
4404 var f = this.getBox(id);
4408 this.eachItem(function(item){
4410 item.setValue(false);
4416 this.setValueForItem(id);
4420 setValueForItem : function(val){
4421 val = String(val).split(',')[0];
4422 this.eachItem(function(item){
4423 item.setValue(val == item.inputValue);
4428 fireChecked : function(){
4429 if(!this.checkTask){
4430 this.checkTask = new Ext.util.DelayedTask(this.bufferChecked, this);
4432 this.checkTask.delay(10);
4436 bufferChecked : function(){
4438 this.eachItem(function(item){
4444 this.fireEvent('change', this, out);
4447 onDestroy : function(){
4449 this.checkTask.cancel();
4450 this.checkTask = null;
4452 Ext.form.RadioGroup.superclass.onDestroy.call(this);
4457 Ext.reg('radiogroup', Ext.form.RadioGroup);
4459 * @class Ext.form.Hidden
\r
4460 * @extends Ext.form.Field
\r
4461 * A basic hidden field for storing hidden values in forms that need to be passed in the form submit.
\r
4463 * Create a new Hidden field.
\r
4464 * @param {Object} config Configuration options
\r
4467 Ext.form.Hidden = Ext.extend(Ext.form.Field, {
\r
4469 inputType : 'hidden',
\r
4472 onRender : function(){
\r
4473 Ext.form.Hidden.superclass.onRender.apply(this, arguments);
\r
4477 initEvents : function(){
\r
4478 this.originalValue = this.getValue();
\r
4481 // These are all private overrides
\r
4482 setSize : Ext.emptyFn,
\r
4483 setWidth : Ext.emptyFn,
\r
4484 setHeight : Ext.emptyFn,
\r
4485 setPosition : Ext.emptyFn,
\r
4486 setPagePosition : Ext.emptyFn,
\r
4487 markInvalid : Ext.emptyFn,
\r
4488 clearInvalid : Ext.emptyFn
\r
4490 Ext.reg('hidden', Ext.form.Hidden);/**
4491 * @class Ext.form.BasicForm
4492 * @extends Ext.util.Observable
4493 * <p>Encapsulates the DOM <form> element at the heart of the {@link Ext.form.FormPanel FormPanel} class, and provides
4494 * input field management, validation, submission, and form loading services.</p>
4495 * <p>By default, Ext Forms are submitted through Ajax, using an instance of {@link Ext.form.Action.Submit}.
4496 * To enable normal browser submission of an Ext Form, use the {@link #standardSubmit} config option.</p>
4497 * <p><b><u>File Uploads</u></b></p>
4498 * <p>{@link #fileUpload File uploads} are not performed using Ajax submission, that
4499 * is they are <b>not</b> performed using XMLHttpRequests. Instead the form is submitted in the standard
4500 * manner with the DOM <tt><form></tt> element temporarily modified to have its
4501 * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
4502 * to a dynamically generated, hidden <tt><iframe></tt> which is inserted into the document
4503 * but removed after the return data has been gathered.</p>
4504 * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
4505 * server is using JSON to send the return object, then the
4506 * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
4507 * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
4508 * <p>Characters which are significant to an HTML parser must be sent as HTML entities, so encode
4509 * "<" as "&lt;", "&" as "&amp;" etc.</p>
4510 * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
4511 * is created containing a <tt>responseText</tt> property in order to conform to the
4512 * requirements of event handlers and callbacks.</p>
4513 * <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>
4514 * and some server technologies (notably JEE) may require some custom processing in order to
4515 * retrieve parameter names and parameter values from the packet content.</p>
4517 * @param {Mixed} el The form element or its id
4518 * @param {Object} config Configuration options
4520 Ext.form.BasicForm = Ext.extend(Ext.util.Observable, {
4522 constructor: function(el, config){
4523 Ext.apply(this, config);
4524 if(Ext.isString(this.paramOrder)){
4525 this.paramOrder = this.paramOrder.split(/[\s,|]/);
4528 * A {@link Ext.util.MixedCollection MixedCollection} containing all the Ext.form.Fields in this form.
4529 * @type MixedCollection
4532 this.items = new Ext.util.MixedCollection(false, function(o){
4533 return o.getItemId();
4537 * @event beforeaction
4538 * Fires before any action is performed. Return false to cancel the action.
4539 * @param {Form} this
4540 * @param {Action} action The {@link Ext.form.Action} to be performed
4544 * @event actionfailed
4545 * Fires when an action fails.
4546 * @param {Form} this
4547 * @param {Action} action The {@link Ext.form.Action} that failed
4551 * @event actioncomplete
4552 * Fires when an action is completed.
4553 * @param {Form} this
4554 * @param {Action} action The {@link Ext.form.Action} that completed
4562 Ext.form.BasicForm.superclass.constructor.call(this);
4566 * @cfg {String} method
4567 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
4570 * @cfg {DataReader} reader
4571 * An Ext.data.DataReader (e.g. {@link Ext.data.XmlReader}) to be used to read
4572 * data when executing 'load' actions. This is optional as there is built-in
4573 * support for processing JSON. For additional information on using an XMLReader
4574 * see the example provided in examples/form/xml-form.html.
4577 * @cfg {DataReader} errorReader
4578 * <p>An Ext.data.DataReader (e.g. {@link Ext.data.XmlReader}) to be used to
4579 * read field error messages returned from 'submit' actions. This is optional
4580 * as there is built-in support for processing JSON.</p>
4581 * <p>The Records which provide messages for the invalid Fields must use the
4582 * Field name (or id) as the Record ID, and must contain a field called 'msg'
4583 * which contains the error message.</p>
4584 * <p>The errorReader does not have to be a full-blown implementation of a
4585 * DataReader. It simply needs to implement a <tt>read(xhr)</tt> function
4586 * which returns an Array of Records in an object with the following
4587 * structure:</p><pre><code>
4589 records: recordArray
4595 * The URL to use for form actions if one isn't supplied in the
4596 * <code>{@link #doAction doAction} options</code>.
4599 * @cfg {Boolean} fileUpload
4600 * Set to true if this form is a file upload.
4601 * <p>File uploads are not performed using normal 'Ajax' techniques, that is they are <b>not</b>
4602 * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
4603 * DOM <tt><form></tt> element temporarily modified to have its
4604 * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
4605 * to a dynamically generated, hidden <tt><iframe></tt> which is inserted into the document
4606 * but removed after the return data has been gathered.</p>
4607 * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
4608 * server is using JSON to send the return object, then the
4609 * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
4610 * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
4611 * <p>Characters which are significant to an HTML parser must be sent as HTML entities, so encode
4612 * "<" as "&lt;", "&" as "&amp;" etc.</p>
4613 * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
4614 * is created containing a <tt>responseText</tt> property in order to conform to the
4615 * requirements of event handlers and callbacks.</p>
4616 * <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>
4617 * and some server technologies (notably JEE) may require some custom processing in order to
4618 * retrieve parameter names and parameter values from the packet content.</p>
4621 * @cfg {Object} baseParams
4622 * <p>Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.</p>
4623 * <p>Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode}.</p>
4626 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
4631 * @cfg {Object} api (Optional) If specified load and submit actions will be handled
4632 * with {@link Ext.form.Action.DirectLoad} and {@link Ext.form.Action.DirectSubmit}.
4633 * Methods which have been imported by Ext.Direct can be specified here to load and submit
4635 * Such as the following:<pre><code>
4637 load: App.ss.MyProfile.load,
4638 submit: App.ss.MyProfile.submit
4641 * <p>Load actions can use <code>{@link #paramOrder}</code> or <code>{@link #paramsAsHash}</code>
4642 * to customize how the load method is invoked.
4643 * Submit actions will always use a standard form submit. The formHandler configuration must
4644 * be set on the associated server-side method which has been imported by Ext.Direct</p>
4648 * @cfg {Array/String} paramOrder <p>A list of params to be executed server side.
4649 * Defaults to <tt>undefined</tt>. Only used for the <code>{@link #api}</code>
4650 * <code>load</code> configuration.</p>
4651 * <br><p>Specify the params in the order in which they must be executed on the
4652 * server-side as either (1) an Array of String values, or (2) a String of params
4653 * delimited by either whitespace, comma, or pipe. For example,
4654 * any of the following would be acceptable:</p><pre><code>
4655 paramOrder: ['param1','param2','param3']
4656 paramOrder: 'param1 param2 param3'
4657 paramOrder: 'param1,param2,param3'
4658 paramOrder: 'param1|param2|param'
4661 paramOrder: undefined,
4664 * @cfg {Boolean} paramsAsHash Only used for the <code>{@link #api}</code>
4665 * <code>load</code> configuration. Send parameters as a collection of named
4666 * arguments (defaults to <tt>false</tt>). Providing a
4667 * <tt>{@link #paramOrder}</tt> nullifies this configuration.
4669 paramsAsHash: false,
4672 * @cfg {String} waitTitle
4673 * The default title to show for the waiting message box (defaults to <tt>'Please Wait...'</tt>)
4675 waitTitle: 'Please Wait...',
4678 activeAction : null,
4681 * @cfg {Boolean} trackResetOnLoad If set to <tt>true</tt>, {@link #reset}() resets to the last loaded
4682 * or {@link #setValues}() data instead of when the form was first created. Defaults to <tt>false</tt>.
4684 trackResetOnLoad : false,
4687 * @cfg {Boolean} standardSubmit
4688 * <p>If set to <tt>true</tt>, standard HTML form submits are used instead
4689 * of XHR (Ajax) style form submissions. Defaults to <tt>false</tt>.</p>
4690 * <br><p><b>Note:</b> When using <code>standardSubmit</code>, the
4691 * <code>options</code> to <code>{@link #submit}</code> are ignored because
4692 * Ext's Ajax infrastracture is bypassed. To pass extra parameters (e.g.
4693 * <code>baseParams</code> and <code>params</code>), utilize hidden fields
4694 * to submit extra data, for example:</p>
4697 standardSubmit: true,
4701 {@link url}: 'myProcess.php',
4708 handler: function(){
4709 var fp = this.ownerCt.ownerCt,
4710 form = fp.getForm();
4711 if (form.isValid()) {
4712 // check if there are baseParams and if
4713 // hiddent items have been added already
4714 if (fp.baseParams && !fp.paramsAdded) {
4715 // add hidden items for all baseParams
4716 for (i in fp.baseParams) {
4720 value: fp.baseParams[i]
4724 // set a custom flag to prevent re-adding
4725 fp.paramsAdded = true;
4727 form.{@link #submit}();
4735 * By default wait messages are displayed with Ext.MessageBox.wait. You can target a specific
4736 * element by passing it or its id or mask the form itself by passing in true.
4738 * @property waitMsgTarget
4742 initEl : function(el){
4743 this.el = Ext.get(el);
4744 this.id = this.el.id || Ext.id();
4745 if(!this.standardSubmit){
4746 this.el.on('submit', this.onSubmit, this);
4748 this.el.addClass('x-form');
4752 * Get the HTML form Element
4753 * @return Ext.Element
4760 onSubmit : function(e){
4765 destroy: function() {
4766 this.items.each(function(f){
4770 this.el.removeAllListeners();
4773 this.purgeListeners();
4777 * Returns true if client-side validation on the form is successful.
4780 isValid : function(){
4782 this.items.each(function(f){
4791 * <p>Returns true if any fields in this form have changed from their original values.</p>
4792 * <p>Note that if this BasicForm was configured with {@link #trackResetOnLoad} then the
4793 * Fields' <i>original values</i> are updated when the values are loaded by {@link #setValues}
4794 * or {@link #loadRecord}.</p>
4797 isDirty : function(){
4799 this.items.each(function(f){
4809 * Performs a predefined action ({@link Ext.form.Action.Submit} or
4810 * {@link Ext.form.Action.Load}) or a custom extension of {@link Ext.form.Action}
4811 * to perform application-specific processing.
4812 * @param {String/Object} actionName The name of the predefined action type,
4813 * or instance of {@link Ext.form.Action} to perform.
4814 * @param {Object} options (optional) The options to pass to the {@link Ext.form.Action}.
4815 * All of the config options listed below are supported by both the
4816 * {@link Ext.form.Action.Submit submit} and {@link Ext.form.Action.Load load}
4817 * actions unless otherwise noted (custom actions could also accept
4818 * other config options):<ul>
4820 * <li><b>url</b> : String<div class="sub-desc">The url for the action (defaults
4821 * to the form's {@link #url}.)</div></li>
4823 * <li><b>method</b> : String<div class="sub-desc">The form method to use (defaults
4824 * to the form's method, or POST if not defined)</div></li>
4826 * <li><b>params</b> : String/Object<div class="sub-desc"><p>The params to pass
4827 * (defaults to the form's baseParams, or none if not defined)</p>
4828 * <p>Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode}.</p></div></li>
4830 * <li><b>headers</b> : Object<div class="sub-desc">Request headers to set for the action
4831 * (defaults to the form's default headers)</div></li>
4833 * <li><b>success</b> : Function<div class="sub-desc">The callback that will
4834 * be invoked after a successful response (see top of
4835 * {@link Ext.form.Action.Submit submit} and {@link Ext.form.Action.Load load}
4836 * for a description of what constitutes a successful response).
4837 * The function is passed the following parameters:<ul>
4838 * <li><tt>form</tt> : Ext.form.BasicForm<div class="sub-desc">The form that requested the action</div></li>
4839 * <li><tt>action</tt> : The {@link Ext.form.Action Action} object which performed the operation.
4840 * <div class="sub-desc">The action object contains these properties of interest:<ul>
4841 * <li><tt>{@link Ext.form.Action#response response}</tt></li>
4842 * <li><tt>{@link Ext.form.Action#result result}</tt> : interrogate for custom postprocessing</li>
4843 * <li><tt>{@link Ext.form.Action#type type}</tt></li>
4844 * </ul></div></li></ul></div></li>
4846 * <li><b>failure</b> : Function<div class="sub-desc">The callback that will be invoked after a
4847 * failed transaction attempt. The function is passed the following parameters:<ul>
4848 * <li><tt>form</tt> : The {@link Ext.form.BasicForm} that requested the action.</li>
4849 * <li><tt>action</tt> : The {@link Ext.form.Action Action} object which performed the operation.
4850 * <div class="sub-desc">The action object contains these properties of interest:<ul>
4851 * <li><tt>{@link Ext.form.Action#failureType failureType}</tt></li>
4852 * <li><tt>{@link Ext.form.Action#response response}</tt></li>
4853 * <li><tt>{@link Ext.form.Action#result result}</tt> : interrogate for custom postprocessing</li>
4854 * <li><tt>{@link Ext.form.Action#type type}</tt></li>
4855 * </ul></div></li></ul></div></li>
4857 * <li><b>scope</b> : Object<div class="sub-desc">The scope in which to call the
4858 * callback functions (The <tt>this</tt> reference for the callback functions).</div></li>
4860 * <li><b>clientValidation</b> : Boolean<div class="sub-desc">Submit Action only.
4861 * Determines whether a Form's fields are validated in a final call to
4862 * {@link Ext.form.BasicForm#isValid isValid} prior to submission. Set to <tt>false</tt>
4863 * to prevent this. If undefined, pre-submission field validation is performed.</div></li></ul>
4865 * @return {BasicForm} this
4867 doAction : function(action, options){
4868 if(Ext.isString(action)){
4869 action = new Ext.form.Action.ACTION_TYPES[action](this, options);
4871 if(this.fireEvent('beforeaction', this, action) !== false){
4872 this.beforeAction(action);
4873 action.run.defer(100, action);
4879 * Shortcut to {@link #doAction do} a {@link Ext.form.Action.Submit submit action}.
4880 * @param {Object} options The options to pass to the action (see {@link #doAction} for details).<br>
4881 * <p><b>Note:</b> this is ignored when using the {@link #standardSubmit} option.</p>
4882 * <p>The following code:</p><pre><code>
4883 myFormPanel.getForm().submit({
4884 clientValidation: true,
4885 url: 'updateConsignment.php',
4887 newStatus: 'delivered'
4889 success: function(form, action) {
4890 Ext.Msg.alert('Success', action.result.msg);
4892 failure: function(form, action) {
4893 switch (action.failureType) {
4894 case Ext.form.Action.CLIENT_INVALID:
4895 Ext.Msg.alert('Failure', 'Form fields may not be submitted with invalid values');
4897 case Ext.form.Action.CONNECT_FAILURE:
4898 Ext.Msg.alert('Failure', 'Ajax communication failed');
4900 case Ext.form.Action.SERVER_INVALID:
4901 Ext.Msg.alert('Failure', action.result.msg);
4906 * would process the following server response for a successful submission:<pre><code>
4908 "success":true, // note this is Boolean, not string
4909 "msg":"Consignment updated"
4912 * and the following server response for a failed submission:<pre><code>
4914 "success":false, // note this is Boolean, not string
4915 "msg":"You do not have permission to perform this operation"
4918 * @return {BasicForm} this
4920 submit : function(options){
4921 if(this.standardSubmit){
4922 var v = this.isValid();
4924 var el = this.el.dom;
4925 if(this.url && Ext.isEmpty(el.action)){
4926 el.action = this.url;
4932 var submitAction = String.format('{0}submit', this.api ? 'direct' : '');
4933 this.doAction(submitAction, options);
4938 * Shortcut to {@link #doAction do} a {@link Ext.form.Action.Load load action}.
4939 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
4940 * @return {BasicForm} this
4942 load : function(options){
4943 var loadAction = String.format('{0}load', this.api ? 'direct' : '');
4944 this.doAction(loadAction, options);
4949 * Persists the values in this form into the passed {@link Ext.data.Record} object in a beginEdit/endEdit block.
4950 * @param {Record} record The record to edit
4951 * @return {BasicForm} this
4953 updateRecord : function(record){
4955 var fs = record.fields;
4956 fs.each(function(f){
4957 var field = this.findField(f.name);
4959 record.set(f.name, field.getValue());
4967 * Loads an {@link Ext.data.Record} into this form by calling {@link #setValues} with the
4968 * {@link Ext.data.Record#data record data}.
4969 * See also {@link #trackResetOnLoad}.
4970 * @param {Record} record The record to load
4971 * @return {BasicForm} this
4973 loadRecord : function(record){
4974 this.setValues(record.data);
4979 beforeAction : function(action){
4980 var o = action.options;
4982 if(this.waitMsgTarget === true){
4983 this.el.mask(o.waitMsg, 'x-mask-loading');
4984 }else if(this.waitMsgTarget){
4985 this.waitMsgTarget = Ext.get(this.waitMsgTarget);
4986 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
4988 Ext.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle);
4994 afterAction : function(action, success){
4995 this.activeAction = null;
4996 var o = action.options;
4998 if(this.waitMsgTarget === true){
5000 }else if(this.waitMsgTarget){
5001 this.waitMsgTarget.unmask();
5003 Ext.MessageBox.updateProgress(1);
5004 Ext.MessageBox.hide();
5011 Ext.callback(o.success, o.scope, [this, action]);
5012 this.fireEvent('actioncomplete', this, action);
5014 Ext.callback(o.failure, o.scope, [this, action]);
5015 this.fireEvent('actionfailed', this, action);
5020 * Find a {@link Ext.form.Field} in this form.
5021 * @param {String} id The value to search for (specify either a {@link Ext.Component#id id},
5022 * {@link Ext.grid.Column#dataIndex dataIndex}, {@link Ext.form.Field#getName name or hiddenName}).
5025 findField : function(id){
5026 var field = this.items.get(id);
5027 if(!Ext.isObject(field)){
5028 this.items.each(function(f){
5029 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
5035 return field || null;
5040 * Mark fields in this form invalid in bulk.
5041 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
5042 * @return {BasicForm} this
5044 markInvalid : function(errors){
5045 if(Ext.isArray(errors)){
5046 for(var i = 0, len = errors.length; i < len; i++){
5047 var fieldError = errors[i];
5048 var f = this.findField(fieldError.id);
5050 f.markInvalid(fieldError.msg);
5056 if(!Ext.isFunction(errors[id]) && (field = this.findField(id))){
5057 field.markInvalid(errors[id]);
5065 * Set values for fields in this form in bulk.
5066 * @param {Array/Object} values Either an array in the form:<pre><code>
5067 [{id:'clientName', value:'Fred. Olsen Lines'},
5068 {id:'portOfLoading', value:'FXT'},
5069 {id:'portOfDischarge', value:'OSL'} ]</code></pre>
5070 * or an object hash of the form:<pre><code>
5072 clientName: 'Fred. Olsen Lines',
5073 portOfLoading: 'FXT',
5074 portOfDischarge: 'OSL'
5076 * @return {BasicForm} this
5078 setValues : function(values){
5079 if(Ext.isArray(values)){ // array of objects
5080 for(var i = 0, len = values.length; i < len; i++){
5082 var f = this.findField(v.id);
5084 f.setValue(v.value);
5085 if(this.trackResetOnLoad){
5086 f.originalValue = f.getValue();
5090 }else{ // object hash
5093 if(!Ext.isFunction(values[id]) && (field = this.findField(id))){
5094 field.setValue(values[id]);
5095 if(this.trackResetOnLoad){
5096 field.originalValue = field.getValue();
5105 * <p>Returns the fields in this form as an object with key/value pairs as they would be submitted using a standard form submit.
5106 * If multiple fields exist with the same name they are returned as an array.</p>
5107 * <p><b>Note:</b> The values are collected from all enabled HTML input elements within the form, <u>not</u> from
5108 * the Ext Field objects. This means that all returned values are Strings (or Arrays of Strings) and that the
5109 * value can potentially be the emptyText of a field.</p>
5110 * @param {Boolean} asString (optional) Pass true to return the values as a string. (defaults to false, returning an Object)
5111 * @return {String/Object}
5113 getValues : function(asString){
5114 var fs = Ext.lib.Ajax.serializeForm(this.el.dom);
5115 if(asString === true){
5118 return Ext.urlDecode(fs);
5122 * Retrieves the fields in the form as a set of key/value pairs, using the {@link Ext.form.Field#getValue getValue()} method.
5123 * If multiple fields exist with the same name they are returned as an array.
5124 * @param {Boolean} dirtyOnly (optional) True to return only fields that are dirty.
5125 * @return {Object} The values in the form
5127 getFieldValues : function(dirtyOnly){
5132 this.items.each(function(f){
5133 if(dirtyOnly !== true || f.isDirty()){
5138 if(Ext.isDefined(key)){
5139 if(Ext.isArray(key)){
5153 * Clears all invalid messages in this form.
5154 * @return {BasicForm} this
5156 clearInvalid : function(){
5157 this.items.each(function(f){
5165 * @return {BasicForm} this
5168 this.items.each(function(f){
5175 * Add Ext.form Components to this form's Collection. This does not result in rendering of
5176 * the passed Component, it just enables the form to validate Fields, and distribute values to
5178 * <p><b>You will not usually call this function. In order to be rendered, a Field must be added
5179 * to a {@link Ext.Container Container}, usually an {@link Ext.form.FormPanel FormPanel}.
5180 * The FormPanel to which the field is added takes care of adding the Field to the BasicForm's
5181 * collection.</b></p>
5182 * @param {Field} field1
5183 * @param {Field} field2 (optional)
5184 * @param {Field} etc (optional)
5185 * @return {BasicForm} this
5188 this.items.addAll(Array.prototype.slice.call(arguments, 0));
5194 * Removes a field from the items collection (does NOT remove its markup).
5195 * @param {Field} field
5196 * @return {BasicForm} this
5198 remove : function(field){
5199 this.items.remove(field);
5204 * Iterates through the {@link Ext.form.Field Field}s which have been {@link #add add}ed to this BasicForm,
5205 * checks them for an id attribute, and calls {@link Ext.form.Field#applyToMarkup} on the existing dom element with that id.
5206 * @return {BasicForm} this
5208 render : function(){
5209 this.items.each(function(f){
5210 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
5211 f.applyToMarkup(f.id);
5218 * Calls {@link Ext#apply} for all fields in this form with the passed object.
5219 * @param {Object} values
5220 * @return {BasicForm} this
5222 applyToFields : function(o){
5223 this.items.each(function(f){
5230 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
5231 * @param {Object} values
5232 * @return {BasicForm} this
5234 applyIfToFields : function(o){
5235 this.items.each(function(f){
5241 callFieldMethod : function(fnName, args){
5243 this.items.each(function(f){
5244 if(Ext.isFunction(f[fnName])){
5245 f[fnName].apply(f, args);
5253 Ext.BasicForm = Ext.form.BasicForm;/**
5254 * @class Ext.form.FormPanel
5255 * @extends Ext.Panel
5256 * <p>Standard form container.</p>
5258 * <p><b><u>Layout</u></b></p>
5259 * <p>By default, FormPanel is configured with <tt>layout:'form'</tt> to use an {@link Ext.layout.FormLayout}
5260 * layout manager, which styles and renders fields and labels correctly. When nesting additional Containers
5261 * within a FormPanel, you should ensure that any descendant Containers which host input Fields use the
5262 * {@link Ext.layout.FormLayout} layout manager.</p>
5264 * <p><b><u>BasicForm</u></b></p>
5265 * <p>Although <b>not listed</b> as configuration options of FormPanel, the FormPanel class accepts all
5266 * of the config options required to configure its internal {@link Ext.form.BasicForm} for:
5267 * <div class="mdetail-params"><ul>
5268 * <li>{@link Ext.form.BasicForm#fileUpload file uploads}</li>
5269 * <li>functionality for {@link Ext.form.BasicForm#doAction loading, validating and submitting} the form</li>
5272 * <p><b>Note</b>: If subclassing FormPanel, any configuration options for the BasicForm must be applied to
5273 * the <tt><b>initialConfig</b></tt> property of the FormPanel. Applying {@link Ext.form.BasicForm BasicForm}
5274 * configuration settings to <b><tt>this</tt></b> will <b>not</b> affect the BasicForm's configuration.</p>
5276 * <p><b><u>Form Validation</u></b></p>
5277 * <p>For information on form validation see the following:</p>
5278 * <div class="mdetail-params"><ul>
5279 * <li>{@link Ext.form.TextField}</li>
5280 * <li>{@link Ext.form.VTypes}</li>
5281 * <li>{@link Ext.form.BasicForm#doAction BasicForm.doAction <b>clientValidation</b> notes}</li>
5282 * <li><tt>{@link Ext.form.FormPanel#monitorValid monitorValid}</tt></li>
5285 * <p><b><u>Form Submission</u></b></p>
5286 * <p>By default, Ext Forms are submitted through Ajax, using {@link Ext.form.Action}. To enable normal browser
5287 * submission of the {@link Ext.form.BasicForm BasicForm} contained in this FormPanel, see the
5288 * <tt><b>{@link Ext.form.BasicForm#standardSubmit standardSubmit}</b></tt> option.</p>
5291 * @param {Object} config Configuration options
5294 Ext.FormPanel = Ext.extend(Ext.Panel, {
5296 * @cfg {String} formId (optional) The id of the FORM tag (defaults to an auto-generated id).
5299 * @cfg {Boolean} hideLabels
5300 * <p><tt>true</tt> to hide field labels by default (sets <tt>display:none</tt>). Defaults to
5301 * <tt>false</tt>.</p>
5302 * <p>Also see {@link Ext.Component}.<tt>{@link Ext.Component#hideLabel hideLabel}</tt>.
5305 * @cfg {Number} labelPad
5306 * The default padding in pixels for field labels (defaults to <tt>5</tt>). <tt>labelPad</tt> only
5307 * applies if <tt>{@link #labelWidth}</tt> is also specified, otherwise it will be ignored.
5310 * @cfg {String} labelSeparator
5311 * See {@link Ext.Component}.<tt>{@link Ext.Component#labelSeparator labelSeparator}</tt>
5314 * @cfg {Number} labelWidth The width of labels in pixels. This property cascades to child containers
5315 * and can be overridden on any child container (e.g., a fieldset can specify a different <tt>labelWidth</tt>
5316 * for its fields) (defaults to <tt>100</tt>).
5319 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
5322 * @cfg {Array} buttons
5323 * An array of {@link Ext.Button}s or {@link Ext.Button} configs used to add buttons to the footer of this FormPanel.<br>
5324 * <p>Buttons in the footer of a FormPanel may be configured with the option <tt>formBind: true</tt>. This causes
5325 * the form's {@link #monitorValid valid state monitor task} to enable/disable those Buttons depending on
5326 * the form's valid/invalid state.</p>
5331 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to <tt>75</tt>).
5333 minButtonWidth : 75,
5336 * @cfg {String} labelAlign The label alignment value used for the <tt>text-align</tt> specification
5337 * for the <b>container</b>. Valid values are <tt>"left</tt>", <tt>"top"</tt> or <tt>"right"</tt>
5338 * (defaults to <tt>"left"</tt>). This property cascades to child <b>containers</b> and can be
5339 * overridden on any child <b>container</b> (e.g., a fieldset can specify a different <tt>labelAlign</tt>
5342 labelAlign : 'left',
5345 * @cfg {Boolean} monitorValid If <tt>true</tt>, the form monitors its valid state <b>client-side</b> and
5346 * regularly fires the {@link #clientvalidation} event passing that state.<br>
5347 * <p>When monitoring valid state, the FormPanel enables/disables any of its configured
5348 * {@link #buttons} which have been configured with <code>formBind: true</code> depending
5349 * on whether the {@link Ext.form.BasicForm#isValid form is valid} or not. Defaults to <tt>false</tt></p>
5351 monitorValid : false,
5354 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
5359 * @cfg {String} layout Defaults to <tt>'form'</tt>. Normally this configuration property should not be altered.
5360 * For additional details see {@link Ext.layout.FormLayout} and {@link Ext.Container#layout Ext.Container.layout}.
5365 initComponent : function(){
5366 this.form = this.createForm();
5367 Ext.FormPanel.superclass.initComponent.call(this);
5371 cls: this.baseCls + '-body',
5372 method : this.method || 'POST',
5373 id : this.formId || Ext.id()
5375 if(this.fileUpload) {
5376 this.bodyCfg.enctype = 'multipart/form-data';
5382 * @event clientvalidation
5383 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5384 * @param {Ext.form.FormPanel} this
5385 * @param {Boolean} valid true if the form has passed client-side validation
5390 this.relayEvents(this.form, ['beforeaction', 'actionfailed', 'actioncomplete']);
5394 createForm : function(){
5395 var config = Ext.applyIf({listeners: {}}, this.initialConfig);
5396 return new Ext.form.BasicForm(null, config);
5400 initFields : function(){
5402 var formPanel = this;
5403 var fn = function(c){
5404 if(formPanel.isField(c)){
5406 }else if(c.findBy && c != formPanel){
5407 formPanel.applySettings(c);
5408 //each check required for check/radio groups.
5409 if(c.items && c.items.each){
5410 c.items.each(fn, this);
5414 this.items.each(fn, this);
5418 applySettings: function(c){
5421 labelAlign: ct.labelAlign,
5422 labelWidth: ct.labelWidth,
5428 getLayoutTarget : function(){
5429 return this.form.el;
5433 * Provides access to the {@link Ext.form.BasicForm Form} which this Panel contains.
5434 * @return {Ext.form.BasicForm} The {@link Ext.form.BasicForm Form} which this Panel contains.
5436 getForm : function(){
5441 onRender : function(ct, position){
5443 Ext.FormPanel.superclass.onRender.call(this, ct, position);
5444 this.form.initEl(this.body);
5448 beforeDestroy : function(){
5449 this.stopMonitoring();
5451 * Don't move this behaviour to BasicForm because it can be used
5454 Ext.destroy(this.form);
5455 this.form.items.clear();
5456 Ext.FormPanel.superclass.beforeDestroy.call(this);
5459 // Determine if a Component is usable as a form Field.
5460 isField : function(c) {
5461 return !!c.setValue && !!c.getValue && !!c.markInvalid && !!c.clearInvalid;
5465 initEvents : function(){
5466 Ext.FormPanel.superclass.initEvents.call(this);
5467 // Listeners are required here to catch bubbling events from children.
5470 add: this.onAddEvent,
5471 remove: this.onRemoveEvent
5473 if(this.monitorValid){ // initialize after render
5474 this.startMonitoring();
5480 Ext.FormPanel.superclass.onAdd.call(this, c);
5485 onAddEvent: function(ct, c){
5492 processAdd : function(c){
5493 // If a single form Field, add it
5494 if(this.isField(c)){
5496 // If a Container, add any Fields it might contain
5498 this.applySettings(c);
5499 this.form.add.apply(this.form, c.findBy(this.isField));
5504 onRemove: function(c){
5505 Ext.FormPanel.superclass.onRemove.call(this, c);
5506 this.processRemove(c);
5509 onRemoveEvent: function(ct, c){
5511 this.processRemove(c);
5516 processRemove : function(c){
5517 // If a single form Field, remove it
5518 if(this.isField(c)){
5519 this.form.remove(c);
5520 // If a Container, its already destroyed by the time it gets here. Remove any references to destroyed fields.
5522 var isDestroyed = function(o) {
5523 return !!o.isDestroyed;
5525 this.form.items.filterBy(isDestroyed, this.form).each(this.form.remove, this.form);
5530 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
5531 * option "monitorValid"
5533 startMonitoring : function(){
5534 if(!this.validTask){
5535 this.validTask = new Ext.util.TaskRunner();
5536 this.validTask.start({
5537 run : this.bindHandler,
5538 interval : this.monitorPoll || 200,
5545 * Stops monitoring of the valid state of this form
5547 stopMonitoring : function(){
5549 this.validTask.stopAll();
5550 this.validTask = null;
5555 * This is a proxy for the underlying BasicForm's {@link Ext.form.BasicForm#load} call.
5556 * @param {Object} options The options to pass to the action (see {@link Ext.form.BasicForm#doAction} for details)
5559 this.form.load.apply(this.form, arguments);
5563 onDisable : function(){
5564 Ext.FormPanel.superclass.onDisable.call(this);
5566 this.form.items.each(function(){
5573 onEnable : function(){
5574 Ext.FormPanel.superclass.onEnable.call(this);
5576 this.form.items.each(function(){
5583 bindHandler : function(){
5585 this.form.items.each(function(f){
5586 if(!f.isValid(true)){
5592 var fitems = this.fbar.items.items;
5593 for(var i = 0, len = fitems.length; i < len; i++){
5594 var btn = fitems[i];
5595 if(btn.formBind === true && btn.disabled === valid){
5596 btn.setDisabled(!valid);
5600 this.fireEvent('clientvalidation', this, valid);
5603 Ext.reg('form', Ext.FormPanel);
5605 Ext.form.FormPanel = Ext.FormPanel;
5607 * @class Ext.form.FieldSet
\r
5608 * @extends Ext.Panel
\r
5609 * Standard container used for grouping items within a {@link Ext.form.FormPanel form}.
\r
5611 var form = new Ext.FormPanel({
\r
5612 title: 'Simple Form with FieldSets',
\r
5613 labelWidth: 75, // label settings here cascade unless overridden
\r
5614 url: 'save-form.php',
\r
5616 bodyStyle:'padding:5px 5px 0',
\r
5618 renderTo: document.body,
\r
5619 layout:'column', // arrange items in columns
\r
5620 defaults: { // defaults applied to items
\r
5623 bodyStyle: 'padding:4px'
\r
5626 // Fieldset in Column 1
\r
5629 title: 'Fieldset 1',
\r
5630 collapsible: true,
\r
5633 anchor: '-20' // leave room for error icon
\r
5635 defaultType: 'textfield',
\r
5637 fieldLabel: 'Field 1'
\r
5639 fieldLabel: 'Field 2'
\r
5641 fieldLabel: 'Field 3'
\r
5645 // Fieldset in Column 2 - Panel inside
\r
5647 title: 'Show Panel', // title, header, or checkboxToggle creates fieldset header
\r
5650 checkboxToggle: true,
\r
5651 collapsed: true, // fieldset initially collapsed
\r
5656 title: 'Panel inside a fieldset',
\r
5664 * @param {Object} config Configuration options
\r
5667 Ext.form.FieldSet = Ext.extend(Ext.Panel, {
\r
5669 * @cfg {Mixed} checkboxToggle <tt>true</tt> to render a checkbox into the fieldset frame just
\r
5670 * in front of the legend to expand/collapse the fieldset when the checkbox is toggled. (defaults
\r
5671 * to <tt>false</tt>).
\r
5672 * <p>A {@link Ext.DomHelper DomHelper} element spec may also be specified to create the checkbox.
\r
5673 * If <tt>true</tt> is specified, the default DomHelper config object used to create the element
\r
5674 * is:</p><pre><code>
\r
5675 * {tag: 'input', type: 'checkbox', name: this.checkboxName || this.id+'-checkbox'}
\r
5679 * @cfg {String} checkboxName The name to assign to the fieldset's checkbox if <tt>{@link #checkboxToggle} = true</tt>
\r
5680 * (defaults to <tt>'[checkbox id]-checkbox'</tt>).
\r
5683 * @cfg {Boolean} collapsible
\r
5684 * <tt>true</tt> to make the fieldset collapsible and have the expand/collapse toggle button automatically
\r
5685 * rendered into the legend element, <tt>false</tt> to keep the fieldset statically sized with no collapse
\r
5686 * button (defaults to <tt>false</tt>). Another option is to configure <tt>{@link #checkboxToggle}</tt>.
\r
5689 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
\r
5692 * @cfg {String} itemCls A css class to apply to the <tt>x-form-item</tt> of fields (see
\r
5693 * {@link Ext.layout.FormLayout}.{@link Ext.layout.FormLayout#fieldTpl fieldTpl} for details).
\r
5694 * This property cascades to child containers.
\r
5697 * @cfg {String} baseCls The base CSS class applied to the fieldset (defaults to <tt>'x-fieldset'</tt>).
\r
5699 baseCls : 'x-fieldset',
\r
5701 * @cfg {String} layout The {@link Ext.Container#layout} to use inside the fieldset (defaults to <tt>'form'</tt>).
\r
5705 * @cfg {Boolean} animCollapse
\r
5706 * <tt>true</tt> to animate the transition when the panel is collapsed, <tt>false</tt> to skip the
\r
5707 * animation (defaults to <tt>false</tt>).
\r
5709 animCollapse : false,
\r
5712 onRender : function(ct, position){
\r
5714 this.el = document.createElement('fieldset');
\r
5715 this.el.id = this.id;
\r
5716 if (this.title || this.header || this.checkboxToggle) {
\r
5717 this.el.appendChild(document.createElement('legend')).className = this.baseCls + '-header';
\r
5721 Ext.form.FieldSet.superclass.onRender.call(this, ct, position);
\r
5723 if(this.checkboxToggle){
\r
5724 var o = typeof this.checkboxToggle == 'object' ?
\r
5725 this.checkboxToggle :
\r
5726 {tag: 'input', type: 'checkbox', name: this.checkboxName || this.id+'-checkbox'};
\r
5727 this.checkbox = this.header.insertFirst(o);
\r
5728 this.checkbox.dom.checked = !this.collapsed;
\r
5729 this.mon(this.checkbox, 'click', this.onCheckClick, this);
\r
5734 onCollapse : function(doAnim, animArg){
\r
5735 if(this.checkbox){
\r
5736 this.checkbox.dom.checked = false;
\r
5738 Ext.form.FieldSet.superclass.onCollapse.call(this, doAnim, animArg);
\r
5743 onExpand : function(doAnim, animArg){
\r
5744 if(this.checkbox){
\r
5745 this.checkbox.dom.checked = true;
\r
5747 Ext.form.FieldSet.superclass.onExpand.call(this, doAnim, animArg);
\r
5751 * This function is called by the fieldset's checkbox when it is toggled (only applies when
\r
5752 * checkboxToggle = true). This method should never be called externally, but can be
\r
5753 * overridden to provide custom behavior when the checkbox is toggled if needed.
\r
5755 onCheckClick : function(){
\r
5756 this[this.checkbox.dom.checked ? 'expand' : 'collapse']();
\r
5760 * @cfg {String/Number} activeItem
\r
5764 * @cfg {Mixed} applyTo
\r
5768 * @cfg {Boolean} bodyBorder
\r
5772 * @cfg {Boolean} border
\r
5776 * @cfg {Boolean/Number} bufferResize
\r
5780 * @cfg {Boolean} collapseFirst
\r
5784 * @cfg {String} defaultType
\r
5788 * @cfg {String} disabledClass
\r
5792 * @cfg {String} elements
\r
5796 * @cfg {Boolean} floating
\r
5800 * @cfg {Boolean} footer
\r
5804 * @cfg {Boolean} frame
\r
5808 * @cfg {Boolean} header
\r
5812 * @cfg {Boolean} headerAsText
\r
5816 * @cfg {Boolean} hideCollapseTool
\r
5820 * @cfg {String} iconCls
\r
5824 * @cfg {Boolean/String} shadow
\r
5828 * @cfg {Number} shadowOffset
\r
5832 * @cfg {Boolean} shim
\r
5836 * @cfg {Object/Array} tbar
\r
5840 * @cfg {Array} tools
\r
5844 * @cfg {Ext.Template/Ext.XTemplate} toolTemplate
\r
5848 * @cfg {String} xtype
\r
5852 * @property header
\r
5856 * @property footer
\r
5864 * @method getBottomToolbar
\r
5868 * @method getTopToolbar
\r
5872 * @method setIconClass
\r
5880 * @event beforeclose
\r
5884 * @event bodyresize
\r
5892 * @event deactivate
\r
5896 Ext.reg('fieldset', Ext.form.FieldSet);
\r
5898 * @class Ext.form.HtmlEditor
5899 * @extends Ext.form.Field
5900 * Provides a lightweight HTML Editor component. Some toolbar features are not supported by Safari and will be
5901 * automatically hidden when needed. These are noted in the config options where appropriate.
5902 * <br><br>The editor's toolbar buttons have tooltips defined in the {@link #buttonTips} property, but they are not
5903 * enabled by default unless the global {@link Ext.QuickTips} singleton is {@link Ext.QuickTips#init initialized}.
5904 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
5905 * supported by this editor.</b>
5906 * <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
5907 * any element that has display set to 'none' can cause problems in Safari and Firefox due to their default iframe reloading bugs.
5908 * <br><br>Example usage:
5910 // Simple example rendered with default options:
5911 Ext.QuickTips.init(); // enable tooltips
5912 new Ext.form.HtmlEditor({
5913 renderTo: Ext.getBody(),
5918 // Passed via xtype into a container and with custom options:
5919 Ext.QuickTips.init(); // enable tooltips
5921 title: 'HTML Editor',
5922 renderTo: Ext.getBody(),
5928 xtype: 'htmleditor',
5929 enableColors: false,
5930 enableAlignments: false
5935 * Create a new HtmlEditor
5936 * @param {Object} config
5940 Ext.form.HtmlEditor = Ext.extend(Ext.form.Field, {
5942 * @cfg {Boolean} enableFormat Enable the bold, italic and underline buttons (defaults to true)
5944 enableFormat : true,
5946 * @cfg {Boolean} enableFontSize Enable the increase/decrease font size buttons (defaults to true)
5948 enableFontSize : true,
5950 * @cfg {Boolean} enableColors Enable the fore/highlight color buttons (defaults to true)
5952 enableColors : true,
5954 * @cfg {Boolean} enableAlignments Enable the left, center, right alignment buttons (defaults to true)
5956 enableAlignments : true,
5958 * @cfg {Boolean} enableLists Enable the bullet and numbered list buttons. Not available in Safari. (defaults to true)
5962 * @cfg {Boolean} enableSourceEdit Enable the switch to source edit button. Not available in Safari. (defaults to true)
5964 enableSourceEdit : true,
5966 * @cfg {Boolean} enableLinks Enable the create link button. Not available in Safari. (defaults to true)
5970 * @cfg {Boolean} enableFont Enable font selection. Not available in Safari. (defaults to true)
5974 * @cfg {String} createLinkText The default text for the create link prompt
5976 createLinkText : 'Please enter the URL for the link:',
5978 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
5980 defaultLinkValue : 'http:/'+'/',
5982 * @cfg {Array} fontFamilies An array of available font families
5991 defaultFont: 'tahoma',
5993 * @cfg {String} defaultValue A default value to be put into the editor to resolve focus issues (defaults to   (Non-breaking space) in Opera and IE6, ​ (Zero-width space) in all other browsers).
5995 defaultValue: (Ext.isOpera || Ext.isIE6) ? ' ' : '​',
5997 // private properties
5999 validationEvent : false,
6001 initialized : false,
6003 sourceEditMode : false,
6004 onFocus : Ext.emptyFn,
6007 defaultAutoCreate : {
6009 style:"width:500px;height:300px;",
6014 initComponent : function(){
6018 * Fires when the editor is fully initialized (including the iframe)
6019 * @param {HtmlEditor} this
6024 * Fires when the editor is first receives the focus. Any insertion must wait
6025 * until after this event.
6026 * @param {HtmlEditor} this
6031 * Fires before the textarea is updated with content from the editor iframe. Return false
6032 * to cancel the sync.
6033 * @param {HtmlEditor} this
6034 * @param {String} html
6039 * Fires before the iframe editor is updated with content from the textarea. Return false
6040 * to cancel the push.
6041 * @param {HtmlEditor} this
6042 * @param {String} html
6047 * Fires when the textarea is updated with content from the editor iframe.
6048 * @param {HtmlEditor} this
6049 * @param {String} html
6054 * Fires when the iframe editor is updated with content from the textarea.
6055 * @param {HtmlEditor} this
6056 * @param {String} html
6060 * @event editmodechange
6061 * Fires when the editor switches edit modes
6062 * @param {HtmlEditor} this
6063 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
6070 createFontOptions : function(){
6071 var buf = [], fs = this.fontFamilies, ff, lc;
6072 for(var i = 0, len = fs.length; i< len; i++){
6074 lc = ff.toLowerCase();
6076 '<option value="',lc,'" style="font-family:',ff,';"',
6077 (this.defaultFont == lc ? ' selected="true">' : '>'),
6082 return buf.join('');
6086 * Protected method that will not generally be called directly. It
6087 * is called when the editor creates its toolbar. Override this method if you need to
6088 * add custom toolbar buttons.
6089 * @param {HtmlEditor} editor
6091 createToolbar : function(editor){
6093 var tipsEnabled = Ext.QuickTips && Ext.QuickTips.isEnabled();
\r
6096 function btn(id, toggle, handler){
6100 iconCls: 'x-edit-'+id,
6101 enableToggle:toggle !== false,
6103 handler:handler||editor.relayBtnCmd,
6104 clickEvent:'mousedown',
6105 tooltip: tipsEnabled ? editor.buttonTips[id] || undefined : undefined,
6106 overflowText: editor.buttonTips[id].title || undefined,
6112 if(this.enableFont && !Ext.isSafari2){
\r
6113 var fontSelectItem = new Ext.Toolbar.Item({
\r
6116 cls:'x-font-select',
\r
6117 html: this.createFontOptions()
\r
6127 if(this.enableFormat){
6135 if(this.enableFontSize){
6138 btn('increasefontsize', false, this.adjustFont),
6139 btn('decreasefontsize', false, this.adjustFont)
6143 if(this.enableColors){
6148 iconCls: 'x-edit-forecolor',
6149 clickEvent:'mousedown',
6150 tooltip: tipsEnabled ? editor.buttonTips.forecolor || undefined : undefined,
6152 menu : new Ext.menu.ColorMenu({
6153 allowReselect: true,
6159 select: function(cp, color){
6160 this.execCmd('forecolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
6164 clickEvent:'mousedown'
6169 iconCls: 'x-edit-backcolor',
6170 clickEvent:'mousedown',
6171 tooltip: tipsEnabled ? editor.buttonTips.backcolor || undefined : undefined,
6173 menu : new Ext.menu.ColorMenu({
6177 allowReselect: true,
6180 select: function(cp, color){
6182 this.execCmd('useCSS', false);
6183 this.execCmd('hilitecolor', color);
6184 this.execCmd('useCSS', true);
6187 this.execCmd(Ext.isOpera ? 'hilitecolor' : 'backcolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
6192 clickEvent:'mousedown'
6198 if(this.enableAlignments){
6202 btn('justifycenter'),
6208 if(this.enableLinks){
6211 btn('createlink', false, this.createLink)
6215 if(this.enableLists){
6218 btn('insertorderedlist'),
6219 btn('insertunorderedlist')
6222 if(this.enableSourceEdit){
6225 btn('sourceedit', true, function(btn){
6226 this.toggleSourceEdit(!this.sourceEditMode);
6232 // build the toolbar
\r
6233 var tb = new Ext.Toolbar({
\r
6234 renderTo: this.wrap.dom.firstChild,
\r
6238 if (fontSelectItem) {
\r
6239 this.fontSelect = fontSelectItem.el;
\r
6241 this.mon(this.fontSelect, 'change', function(){
\r
6242 var font = this.fontSelect.dom.value;
\r
6243 this.relayCmd('fontname', font);
\r
6244 this.deferFocus();
\r
6249 // stop form submits
\r
6250 this.mon(tb.el, 'click', function(e){
\r
6251 e.preventDefault();
\r
6257 onDisable: function(){
6259 Ext.form.HtmlEditor.superclass.onDisable.call(this);
6262 onEnable: function(){
6264 Ext.form.HtmlEditor.superclass.onEnable.call(this);
6267 setReadOnly: function(readOnly){
6269 Ext.form.HtmlEditor.superclass.setReadOnly.call(this, readOnly);
6270 if(this.initialized){
\r
6271 this.setDesignMode(!readOnly);
\r
6272 var bd = this.getEditorBody();
\r
6274 bd.style.cursor = this.readOnly ? 'default' : 'text';
\r
6276 this.disableItems(readOnly);
\r
6281 * Protected method that will not generally be called directly. It
6282 * is called when the editor initializes the iframe with HTML contents. Override this method if you
6283 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
6285 * Note: IE8-Standards has unwanted scroller behavior, so the default meta tag forces IE7 compatibility
\r
6287 getDocMarkup : function(){
6288 return '<html><head><meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" /><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
6292 getEditorBody : function(){
6293 var doc = this.getDoc();
6294 return doc.body || doc.documentElement;
6298 getDoc : function(){
6299 return Ext.isIE ? this.getWin().document : (this.iframe.contentDocument || this.getWin().document);
6303 getWin : function(){
6304 return Ext.isIE ? this.iframe.contentWindow : window.frames[this.iframe.name];
6308 onRender : function(ct, position){
6309 Ext.form.HtmlEditor.superclass.onRender.call(this, ct, position);
6310 this.el.dom.style.border = '0 none';
6311 this.el.dom.setAttribute('tabIndex', -1);
6312 this.el.addClass('x-hidden');
6313 if(Ext.isIE){ // fix IE 1px bogus margin
6314 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
6316 this.wrap = this.el.wrap({
6317 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
6320 this.createToolbar(this);
6322 this.disableItems(true);
6326 this.createIFrame();
6329 var sz = this.el.getSize();
6330 this.setSize(sz.width, this.height || sz.height);
6332 this.resizeEl = this.positionEl = this.wrap;
6335 createIFrame: function(){
6336 var iframe = document.createElement('iframe');
6337 iframe.name = Ext.id();
6338 iframe.frameBorder = '0';
6339 iframe.style.overflow = 'auto';
\r
6341 this.wrap.dom.appendChild(iframe);
6342 this.iframe = iframe;
6344 this.monitorTask = Ext.TaskMgr.start({
6345 run: this.checkDesignMode,
6351 initFrame : function(){
6352 Ext.TaskMgr.stop(this.monitorTask);
6353 var doc = this.getDoc();
6354 this.win = this.getWin();
6357 doc.write(this.getDocMarkup());
6360 var task = { // must defer to wait for browser to be ready
6362 var doc = this.getDoc();
6363 if(doc.body || doc.readyState == 'complete'){
6364 Ext.TaskMgr.stop(task);
6365 this.setDesignMode(true);
6366 this.initEditor.defer(10, this);
6373 Ext.TaskMgr.start(task);
6377 checkDesignMode : function(){
6378 if(this.wrap && this.wrap.dom.offsetWidth){
6379 var doc = this.getDoc();
6383 if(!doc.editorInitialized || this.getDesignMode() != 'on'){
6390 * set current design mode. To enable, mode can be true or 'on', off otherwise
\r
6392 setDesignMode : function(mode){
\r
6394 if(doc = this.getDoc()){
\r
6395 if(this.readOnly){
\r
6398 doc.designMode = (/on|true/i).test(String(mode).toLowerCase()) ?'on':'off';
\r
6404 getDesignMode : function(){
6405 var doc = this.getDoc();
\r
6406 if(!doc){ return ''; }
\r
6407 return String(doc.designMode).toLowerCase();
\r
6411 disableItems: function(disabled){
6412 if(this.fontSelect){
6413 this.fontSelect.dom.disabled = disabled;
6415 this.tb.items.each(function(item){
6416 if(item.getItemId() != 'sourceedit'){
6417 item.setDisabled(disabled);
6423 onResize : function(w, h){
6424 Ext.form.HtmlEditor.superclass.onResize.apply(this, arguments);
6425 if(this.el && this.iframe){
6426 if(Ext.isNumber(w)){
6427 var aw = w - this.wrap.getFrameWidth('lr');
6428 this.el.setWidth(aw);
6429 this.tb.setWidth(aw);
6430 this.iframe.style.width = Math.max(aw, 0) + 'px';
6432 if(Ext.isNumber(h)){
6433 var ah = h - this.wrap.getFrameWidth('tb') - this.tb.el.getHeight();
6434 this.el.setHeight(ah);
6435 this.iframe.style.height = Math.max(ah, 0) + 'px';
6436 var bd = this.getEditorBody();
6438 bd.style.height = Math.max((ah - (this.iframePad*2)), 0) + 'px';
6445 * Toggles the editor between standard and source edit mode.
6446 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
6448 toggleSourceEdit : function(sourceEditMode){
6449 if(sourceEditMode === undefined){
6450 sourceEditMode = !this.sourceEditMode;
6452 this.sourceEditMode = sourceEditMode === true;
6453 var btn = this.tb.getComponent('sourceedit');
6455 if(btn.pressed !== this.sourceEditMode){
6456 btn.toggle(this.sourceEditMode);
6461 if(this.sourceEditMode){
6462 this.disableItems(true);
6464 this.iframe.className = 'x-hidden';
6465 this.el.removeClass('x-hidden');
6466 this.el.dom.removeAttribute('tabIndex');
6469 if(this.initialized){
6470 this.disableItems(this.readOnly);
6473 this.iframe.className = '';
6474 this.el.addClass('x-hidden');
6475 this.el.dom.setAttribute('tabIndex', -1);
6478 var lastSize = this.lastSize;
6480 delete this.lastSize;
6481 this.setSize(lastSize);
6483 this.fireEvent('editmodechange', this, this.sourceEditMode);
6486 // private used internally
6487 createLink : function(){
6488 var url = prompt(this.createLinkText, this.defaultLinkValue);
6489 if(url && url != 'http:/'+'/'){
6490 this.relayCmd('createlink', url);
6495 initEvents : function(){
6496 this.originalValue = this.getValue();
6500 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
6503 markInvalid : Ext.emptyFn,
6506 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
6509 clearInvalid : Ext.emptyFn,
6511 // docs inherit from Field
6512 setValue : function(v){
6513 Ext.form.HtmlEditor.superclass.setValue.call(this, v);
6519 * Protected method that will not generally be called directly. If you need/want
6520 * custom HTML cleanup, this is the method you should override.
6521 * @param {String} html The HTML to be cleaned
6522 * @return {String} The cleaned HTML
6524 cleanHtml: function(html) {
6525 html = String(html);
6526 if(Ext.isWebKit){ // strip safari nonsense
6527 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
6531 * Neat little hack. Strips out all the non-digit characters from the default
6532 * value and compares it to the character code of the first character in the string
6533 * because it can cause encoding issues when posted to the server.
6535 if(html.charCodeAt(0) == this.defaultValue.replace(/\D/g, '')){
6536 html = html.substring(1);
6542 * Protected method that will not generally be called directly. Syncs the contents
6543 * of the editor iframe with the textarea.
6545 syncValue : function(){
6546 if(this.initialized){
6547 var bd = this.getEditorBody();
6548 var html = bd.innerHTML;
6550 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
6551 var m = bs.match(/text-align:(.*?);/i);
6553 html = '<div style="'+m[0]+'">' + html + '</div>';
6556 html = this.cleanHtml(html);
6557 if(this.fireEvent('beforesync', this, html) !== false){
6558 this.el.dom.value = html;
6559 this.fireEvent('sync', this, html);
6564 //docs inherit from Field
6565 getValue : function() {
6566 this[this.sourceEditMode ? 'pushValue' : 'syncValue']();
6567 return Ext.form.HtmlEditor.superclass.getValue.call(this);
6571 * Protected method that will not generally be called directly. Pushes the value of the textarea
6572 * into the iframe editor.
6574 pushValue : function(){
6575 if(this.initialized){
6576 var v = this.el.dom.value;
6577 if(!this.activated && v.length < 1){
6578 v = this.defaultValue;
6580 if(this.fireEvent('beforepush', this, v) !== false){
6581 this.getEditorBody().innerHTML = v;
6583 // Gecko hack, see: https://bugzilla.mozilla.org/show_bug.cgi?id=232791#c8
6584 this.setDesignMode(false); //toggle off first
\r
6587 this.setDesignMode(true);
\r
6588 this.fireEvent('push', this, v);
6595 deferFocus : function(){
6596 this.focus.defer(10, this);
6599 // docs inherit from Field
6601 if(this.win && !this.sourceEditMode){
6609 initEditor : function(){
6610 //Destroying the component during/before initEditor can cause issues.
6612 var dbody = this.getEditorBody(),
6613 ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat'),
6617 ss['background-attachment'] = 'fixed'; // w3c
6618 dbody.bgProperties = 'fixed'; // ie
6620 Ext.DomHelper.applyStyles(dbody, ss);
6622 doc = this.getDoc();
6626 Ext.EventManager.removeAll(doc);
6631 * We need to use createDelegate here, because when using buffer, the delayed task is added
6632 * as a property to the function. When the listener is removed, the task is deleted from the function.
6633 * Since onEditorEvent is shared on the prototype, if we have multiple html editors, the first time one of the editors
6634 * is destroyed, it causes the fn to be deleted from the prototype, which causes errors. Essentially, we're just anonymizing the function.
6636 fn = this.onEditorEvent.createDelegate(this);
6637 Ext.EventManager.on(doc, {
6646 Ext.EventManager.on(doc, 'keypress', this.applyCommand, this);
6648 if(Ext.isIE || Ext.isWebKit || Ext.isOpera){
6649 Ext.EventManager.on(doc, 'keydown', this.fixKeys, this);
6651 doc.editorInitialized = true;
6652 this.initialized = true;
6654 this.setReadOnly(this.readOnly);
6655 this.fireEvent('initialize', this);
6660 onDestroy : function(){
6661 if(this.monitorTask){
6662 Ext.TaskMgr.stop(this.monitorTask);
6665 Ext.destroy(this.tb);
6666 var doc = this.getDoc();
6669 Ext.EventManager.removeAll(doc);
6670 for (var prop in doc){
6676 this.wrap.dom.innerHTML = '';
6682 this.el.removeAllListeners();
6685 this.purgeListeners();
6689 onFirstFocus : function(){
6690 this.activated = true;
6691 this.disableItems(this.readOnly);
6692 if(Ext.isGecko){ // prevent silly gecko errors
6694 var s = this.win.getSelection();
6695 if(!s.focusNode || s.focusNode.nodeType != 3){
6696 var r = s.getRangeAt(0);
6697 r.selectNodeContents(this.getEditorBody());
6702 this.execCmd('useCSS', true);
6703 this.execCmd('styleWithCSS', false);
6706 this.fireEvent('activate', this);
6710 adjustFont: function(btn){
6711 var adjust = btn.getItemId() == 'increasefontsize' ? 1 : -1,
6712 doc = this.getDoc(),
6713 v = parseInt(doc.queryCommandValue('FontSize') || 2, 10);
6714 if((Ext.isSafari && !Ext.isSafari2) || Ext.isChrome || Ext.isAir){
6716 // 1 = 10px, 2 = 13px, 3 = 16px, 4 = 18px, 5 = 24px, 6 = 32px
6730 v = v.constrain(1, 6);
6732 if(Ext.isSafari){ // safari
6735 v = Math.max(1, v+adjust) + (Ext.isSafari ? 'px' : 0);
6737 this.execCmd('FontSize', v);
6741 onEditorEvent : function(e){
6742 this.updateToolbar();
6747 * Protected method that will not generally be called directly. It triggers
6748 * a toolbar update by reading the markup state of the current selection in the editor.
6750 updateToolbar: function(){
6756 if(!this.activated){
6757 this.onFirstFocus();
6761 var btns = this.tb.items.map,
6762 doc = this.getDoc();
6764 if(this.enableFont && !Ext.isSafari2){
6765 var name = (doc.queryCommandValue('FontName')||this.defaultFont).toLowerCase();
6766 if(name != this.fontSelect.dom.value){
6767 this.fontSelect.dom.value = name;
6770 if(this.enableFormat){
6771 btns.bold.toggle(doc.queryCommandState('bold'));
6772 btns.italic.toggle(doc.queryCommandState('italic'));
6773 btns.underline.toggle(doc.queryCommandState('underline'));
6775 if(this.enableAlignments){
6776 btns.justifyleft.toggle(doc.queryCommandState('justifyleft'));
6777 btns.justifycenter.toggle(doc.queryCommandState('justifycenter'));
6778 btns.justifyright.toggle(doc.queryCommandState('justifyright'));
6780 if(!Ext.isSafari2 && this.enableLists){
6781 btns.insertorderedlist.toggle(doc.queryCommandState('insertorderedlist'));
6782 btns.insertunorderedlist.toggle(doc.queryCommandState('insertunorderedlist'));
6785 Ext.menu.MenuMgr.hideAll();
6791 relayBtnCmd : function(btn){
6792 this.relayCmd(btn.getItemId());
6796 * Executes a Midas editor command on the editor document and performs necessary focus and
6797 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
6798 * @param {String} cmd The Midas command
6799 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
6801 relayCmd : function(cmd, value){
6804 this.execCmd(cmd, value);
6805 this.updateToolbar();
6810 * Executes a Midas editor command directly on the editor document.
6811 * For visual commands, you should use {@link #relayCmd} instead.
6812 * <b>This should only be called after the editor is initialized.</b>
6813 * @param {String} cmd The Midas command
6814 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
6816 execCmd : function(cmd, value){
6817 var doc = this.getDoc();
6818 doc.execCommand(cmd, false, value === undefined ? null : value);
6823 applyCommand : function(e){
6825 var c = e.getCharCode(), cmd;
6827 c = String.fromCharCode(c);
6850 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
6852 * @param {String} text
6854 insertAtCursor : function(text){
6855 if(!this.activated){
6860 var doc = this.getDoc(),
6861 r = doc.selection.createRange();
6869 this.execCmd('InsertHTML', text);
6875 fixKeys : function(){ // load time branching for fastest keydown performance
6879 doc = this.getDoc(),
6883 r = doc.selection.createRange();
6886 r.pasteHTML(' ');
6889 }else if(k == e.ENTER){
6890 r = doc.selection.createRange();
6892 var target = r.parentElement();
6893 if(!target || target.tagName.toLowerCase() != 'li'){
6895 r.pasteHTML('<br />');
6902 }else if(Ext.isOpera){
6908 this.execCmd('InsertHTML',' ');
6912 }else if(Ext.isWebKit){
6917 this.execCmd('InsertText','\t');
6919 }else if(k == e.ENTER){
6921 this.execCmd('InsertHtml','<br /><br />');
6929 * Returns the editor's toolbar. <b>This is only available after the editor has been rendered.</b>
6930 * @return {Ext.Toolbar}
6932 getToolbar : function(){
6937 * Object collection of toolbar tooltips for the buttons in the editor. The key
6938 * is the command id associated with that button and the value is a valid QuickTips object.
6943 title: 'Bold (Ctrl+B)',
6944 text: 'Make the selected text bold.',
6945 cls: 'x-html-editor-tip'
6948 title: 'Italic (Ctrl+I)',
6949 text: 'Make the selected text italic.',
6950 cls: 'x-html-editor-tip'
6958 title: 'Bold (Ctrl+B)',
6959 text: 'Make the selected text bold.',
6960 cls: 'x-html-editor-tip'
6963 title: 'Italic (Ctrl+I)',
6964 text: 'Make the selected text italic.',
6965 cls: 'x-html-editor-tip'
6968 title: 'Underline (Ctrl+U)',
6969 text: 'Underline the selected text.',
6970 cls: 'x-html-editor-tip'
6972 increasefontsize : {
6974 text: 'Increase the font size.',
6975 cls: 'x-html-editor-tip'
6977 decreasefontsize : {
6978 title: 'Shrink Text',
6979 text: 'Decrease the font size.',
6980 cls: 'x-html-editor-tip'
6983 title: 'Text Highlight Color',
6984 text: 'Change the background color of the selected text.',
6985 cls: 'x-html-editor-tip'
6988 title: 'Font Color',
6989 text: 'Change the color of the selected text.',
6990 cls: 'x-html-editor-tip'
6993 title: 'Align Text Left',
6994 text: 'Align text to the left.',
6995 cls: 'x-html-editor-tip'
6998 title: 'Center Text',
6999 text: 'Center text in the editor.',
7000 cls: 'x-html-editor-tip'
7003 title: 'Align Text Right',
7004 text: 'Align text to the right.',
7005 cls: 'x-html-editor-tip'
7007 insertunorderedlist : {
7008 title: 'Bullet List',
7009 text: 'Start a bulleted list.',
7010 cls: 'x-html-editor-tip'
7012 insertorderedlist : {
7013 title: 'Numbered List',
7014 text: 'Start a numbered list.',
7015 cls: 'x-html-editor-tip'
7019 text: 'Make the selected text a hyperlink.',
7020 cls: 'x-html-editor-tip'
7023 title: 'Source Edit',
7024 text: 'Switch to source editing mode.',
7025 cls: 'x-html-editor-tip'
7029 // hide stuff that is not compatible
7047 * @cfg {String} fieldClass @hide
7050 * @cfg {String} focusClass @hide
7053 * @cfg {String} autoCreate @hide
7056 * @cfg {String} inputType @hide
7059 * @cfg {String} invalidClass @hide
7062 * @cfg {String} invalidText @hide
7065 * @cfg {String} msgFx @hide
7068 * @cfg {String} validateOnBlur @hide
7071 * @cfg {Boolean} allowDomMove @hide
7074 * @cfg {String} applyTo @hide
7077 * @cfg {String} autoHeight @hide
7080 * @cfg {String} autoWidth @hide
7083 * @cfg {String} cls @hide
7086 * @cfg {String} disabled @hide
7089 * @cfg {String} disabledClass @hide
7092 * @cfg {String} msgTarget @hide
7095 * @cfg {String} readOnly @hide
7098 * @cfg {String} style @hide
7101 * @cfg {String} validationDelay @hide
7104 * @cfg {String} validationEvent @hide
7107 * @cfg {String} tabIndex @hide
7110 * @property disabled
7114 * @method applyToMarkup
7134 * @method setDisabled
7142 Ext.reg('htmleditor', Ext.form.HtmlEditor);/**
\r
7143 * @class Ext.form.TimeField
\r
7144 * @extends Ext.form.ComboBox
\r
7145 * Provides a time input field with a time dropdown and automatic time validation. Example usage:
\r
7147 new Ext.form.TimeField({
\r
7148 minValue: '9:00 AM',
\r
7149 maxValue: '6:00 PM',
\r
7154 * Create a new TimeField
\r
7155 * @param {Object} config
\r
7156 * @xtype timefield
\r
7158 Ext.form.TimeField = Ext.extend(Ext.form.ComboBox, {
\r
7160 * @cfg {Date/String} minValue
\r
7161 * The minimum allowed time. Can be either a Javascript date object with a valid time value or a string
\r
7162 * time in a valid format -- see {@link #format} and {@link #altFormats} (defaults to undefined).
\r
7164 minValue : undefined,
\r
7166 * @cfg {Date/String} maxValue
\r
7167 * The maximum allowed time. Can be either a Javascript date object with a valid time value or a string
\r
7168 * time in a valid format -- see {@link #format} and {@link #altFormats} (defaults to undefined).
\r
7170 maxValue : undefined,
\r
7172 * @cfg {String} minText
\r
7173 * The error text to display when the date in the cell is before minValue (defaults to
\r
7174 * 'The time in this field must be equal to or after {0}').
\r
7176 minText : "The time in this field must be equal to or after {0}",
\r
7178 * @cfg {String} maxText
\r
7179 * The error text to display when the time is after maxValue (defaults to
\r
7180 * 'The time in this field must be equal to or before {0}').
\r
7182 maxText : "The time in this field must be equal to or before {0}",
\r
7184 * @cfg {String} invalidText
\r
7185 * The error text to display when the time in the field is invalid (defaults to
\r
7186 * '{value} is not a valid time').
\r
7188 invalidText : "{0} is not a valid time",
\r
7190 * @cfg {String} format
\r
7191 * The default time format string which can be overriden for localization support. The format must be
\r
7192 * valid according to {@link Date#parseDate} (defaults to 'g:i A', e.g., '3:15 PM'). For 24-hour time
\r
7193 * format try 'H:i' instead.
\r
7197 * @cfg {String} altFormats
\r
7198 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
\r
7199 * 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
7201 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
7203 * @cfg {Number} increment
\r
7204 * The number of minutes between each time value in the list (defaults to 15).
\r
7208 // private override
\r
7210 // private override
\r
7211 triggerAction: 'all',
\r
7212 // private override
\r
7215 // private - This is the date to use when generating time values in the absence of either minValue
\r
7216 // or maxValue. Using the current date causes DST issues on DST boundary dates, so this is an
\r
7217 // arbitrary "safe" date that can be any date aside from DST boundary dates.
\r
7218 initDate: '1/1/2008',
\r
7221 initComponent : function(){
\r
7222 if(Ext.isDefined(this.minValue)){
\r
7223 this.setMinValue(this.minValue, true);
\r
7225 if(Ext.isDefined(this.maxValue)){
\r
7226 this.setMaxValue(this.maxValue, true);
\r
7229 this.generateStore(true);
\r
7231 Ext.form.TimeField.superclass.initComponent.call(this);
\r
7235 * Replaces any existing {@link #minValue} with the new time and refreshes the store.
\r
7236 * @param {Date/String} value The minimum time that can be selected
\r
7238 setMinValue: function(value, /* private */ initial){
\r
7239 this.setLimit(value, true, initial);
\r
7244 * Replaces any existing {@link #maxValue} with the new time and refreshes the store.
\r
7245 * @param {Date/String} value The maximum time that can be selected
\r
7247 setMaxValue: function(value, /* private */ initial){
\r
7248 this.setLimit(value, false, initial);
\r
7253 generateStore: function(initial){
\r
7254 var min = this.minValue || new Date(this.initDate).clearTime(),
\r
7255 max = this.maxValue || new Date(this.initDate).clearTime().add('mi', (24 * 60) - 1),
\r
7258 while(min <= max){
\r
7259 times.push(min.dateFormat(this.format));
\r
7260 min = min.add('mi', this.increment);
\r
7262 this.bindStore(times, initial);
\r
7266 setLimit: function(value, isMin, initial){
\r
7268 if(Ext.isString(value)){
\r
7269 d = this.parseDate(value);
\r
7270 }else if(Ext.isDate(value)){
\r
7274 var val = new Date(this.initDate).clearTime();
\r
7275 val.setHours(d.getHours(), d.getMinutes(), isMin ? 0 : 59, 0);
\r
7276 this[isMin ? 'minValue' : 'maxValue'] = val;
\r
7278 this.generateStore();
\r
7284 getValue : function(){
\r
7285 var v = Ext.form.TimeField.superclass.getValue.call(this);
\r
7286 return this.formatDate(this.parseDate(v)) || '';
\r
7290 setValue : function(value){
\r
7291 return Ext.form.TimeField.superclass.setValue.call(this, this.formatDate(this.parseDate(value)));
\r
7294 // private overrides
\r
7295 validateValue : Ext.form.DateField.prototype.validateValue,
\r
7296 parseDate : Ext.form.DateField.prototype.parseDate,
\r
7297 formatDate : Ext.form.DateField.prototype.formatDate,
\r
7300 beforeBlur : function(){
\r
7301 var v = this.parseDate(this.getRawValue());
\r
7303 this.setValue(v.dateFormat(this.format));
\r
7305 Ext.form.TimeField.superclass.beforeBlur.call(this);
\r
7309 * @cfg {Boolean} grow @hide
\r
7312 * @cfg {Number} growMin @hide
\r
7315 * @cfg {Number} growMax @hide
\r
7319 * @method autoSize
\r
7322 Ext.reg('timefield', Ext.form.TimeField);/**
7323 * @class Ext.form.Label
7324 * @extends Ext.BoxComponent
7325 * Basic Label field.
7327 * Creates a new Label
7328 * @param {Ext.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
7329 * 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
7330 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
7333 Ext.form.Label = Ext.extend(Ext.BoxComponent, {
7335 * @cfg {String} text The plain text to display within the label (defaults to ''). If you need to include HTML
7336 * tags within the label's innerHTML, use the {@link #html} config instead.
7339 * @cfg {String} forId The id of the input element to which this label will be bound via the standard HTML 'for'
7340 * attribute. If not specified, the attribute will not be added to the label.
7343 * @cfg {String} html An HTML fragment that will be used as the label's innerHTML (defaults to '').
7344 * Note that if {@link #text} is specified it will take precedence and this value will be ignored.
7348 onRender : function(ct, position){
7350 this.el = document.createElement('label');
7351 this.el.id = this.getId();
7352 this.el.innerHTML = this.text ? Ext.util.Format.htmlEncode(this.text) : (this.html || '');
7354 this.el.setAttribute('for', this.forId);
7357 Ext.form.Label.superclass.onRender.call(this, ct, position);
7361 * Updates the label's innerHTML with the specified string.
7362 * @param {String} text The new label text
7363 * @param {Boolean} encode (optional) False to skip HTML-encoding the text when rendering it
7364 * to the label (defaults to true which encodes the value). This might be useful if you want to include
7365 * tags in the label's innerHTML rather than rendering them as string literals per the default logic.
7366 * @return {Label} this
7368 setText : function(t, encode){
7369 var e = encode === false;
7370 this[!e ? 'text' : 'html'] = t;
7371 delete this[e ? 'text' : 'html'];
7373 this.el.dom.innerHTML = encode !== false ? Ext.util.Format.htmlEncode(t) : t;
7379 Ext.reg('label', Ext.form.Label);/**
7380 * @class Ext.form.Action
7381 * <p>The subclasses of this class provide actions to perform upon {@link Ext.form.BasicForm Form}s.</p>
7382 * <p>Instances of this class are only created by a {@link Ext.form.BasicForm Form} when
7383 * the Form needs to perform an action such as submit or load. The Configuration options
7384 * listed for this class are set through the Form's action methods: {@link Ext.form.BasicForm#submit submit},
7385 * {@link Ext.form.BasicForm#load load} and {@link Ext.form.BasicForm#doAction doAction}</p>
7386 * <p>The instance of Action which performed the action is passed to the success
7387 * and failure callbacks of the Form's action methods ({@link Ext.form.BasicForm#submit submit},
7388 * {@link Ext.form.BasicForm#load load} and {@link Ext.form.BasicForm#doAction doAction}),
7389 * and to the {@link Ext.form.BasicForm#actioncomplete actioncomplete} and
7390 * {@link Ext.form.BasicForm#actionfailed actionfailed} event handlers.</p>
7392 Ext.form.Action = function(form, options){
7394 this.options = options || {};
7398 * Failure type returned when client side validation of the Form fails
7399 * thus aborting a submit action. Client side validation is performed unless
7400 * {@link #clientValidation} is explicitly set to <tt>false</tt>.
7404 Ext.form.Action.CLIENT_INVALID = 'client';
7406 * <p>Failure type returned when server side processing fails and the {@link #result}'s
7407 * <tt style="font-weight:bold">success</tt> property is set to <tt>false</tt>.</p>
7408 * <p>In the case of a form submission, field-specific error messages may be returned in the
7409 * {@link #result}'s <tt style="font-weight:bold">errors</tt> property.</p>
7413 Ext.form.Action.SERVER_INVALID = 'server';
7415 * Failure type returned when a communication error happens when attempting
7416 * to send a request to the remote server. The {@link #response} may be examined to
7417 * provide further information.
7421 Ext.form.Action.CONNECT_FAILURE = 'connect';
7423 * Failure type returned when the response's <tt style="font-weight:bold">success</tt>
7424 * property is set to <tt>false</tt>, or no field values are returned in the response's
7425 * <tt style="font-weight:bold">data</tt> property.
7429 Ext.form.Action.LOAD_FAILURE = 'load';
7431 Ext.form.Action.prototype = {
7433 * @cfg {String} url The URL that the Action is to invoke.
7436 * @cfg {Boolean} reset When set to <tt><b>true</b></tt>, causes the Form to be
7437 * {@link Ext.form.BasicForm.reset reset} on Action success. If specified, this happens
7438 * <b>before</b> the {@link #success} callback is called and before the Form's
7439 * {@link Ext.form.BasicForm.actioncomplete actioncomplete} event fires.
7442 * @cfg {String} method The HTTP method to use to access the requested URL. Defaults to the
7443 * {@link Ext.form.BasicForm}'s method, or if that is not specified, the underlying DOM form's method.
7446 * @cfg {Mixed} params <p>Extra parameter values to pass. These are added to the Form's
7447 * {@link Ext.form.BasicForm#baseParams} and passed to the specified URL along with the Form's
7449 * <p>Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode}.</p>
7452 * @cfg {Number} timeout The number of seconds to wait for a server response before
7453 * failing with the {@link #failureType} as {@link #Action.CONNECT_FAILURE}. If not specified,
7454 * defaults to the configured <tt>{@link Ext.form.BasicForm#timeout timeout}</tt> of the
7455 * {@link Ext.form.BasicForm form}.
7458 * @cfg {Function} success The function to call when a valid success return packet is recieved.
7459 * The function is passed the following parameters:<ul class="mdetail-params">
7460 * <li><b>form</b> : Ext.form.BasicForm<div class="sub-desc">The form that requested the action</div></li>
7461 * <li><b>action</b> : Ext.form.Action<div class="sub-desc">The Action class. The {@link #result}
7462 * property of this object may be examined to perform custom postprocessing.</div></li>
7466 * @cfg {Function} failure The function to call when a failure packet was recieved, or when an
7467 * error ocurred in the Ajax communication.
7468 * The function is passed the following parameters:<ul class="mdetail-params">
7469 * <li><b>form</b> : Ext.form.BasicForm<div class="sub-desc">The form that requested the action</div></li>
7470 * <li><b>action</b> : Ext.form.Action<div class="sub-desc">The Action class. If an Ajax
7471 * error ocurred, the failure type will be in {@link #failureType}. The {@link #result}
7472 * property of this object may be examined to perform custom postprocessing.</div></li>
7476 * @cfg {Object} scope The scope in which to call the callback functions (The <tt>this</tt> reference
7477 * for the callback functions).
7480 * @cfg {String} waitMsg The message to be displayed by a call to {@link Ext.MessageBox#wait}
7481 * during the time the action is being processed.
7484 * @cfg {String} waitTitle The title to be displayed by a call to {@link Ext.MessageBox#wait}
7485 * during the time the action is being processed.
7489 * The type of action this Action instance performs.
7490 * Currently only "submit" and "load" are supported.
7495 * The type of failure detected will be one of these: {@link #CLIENT_INVALID},
7496 * {@link #SERVER_INVALID}, {@link #CONNECT_FAILURE}, or {@link #LOAD_FAILURE}. Usage:
7498 var fp = new Ext.form.FormPanel({
7503 handler: function(){
7504 if(fp.getForm().isValid()){
7505 fp.getForm().submit({
7506 url: 'form-submit.php',
7507 waitMsg: 'Submitting your data...',
7508 success: function(form, action){
7509 // server responded with success = true
7510 var result = action.{@link #result};
7512 failure: function(form, action){
7513 if (action.{@link #failureType} === Ext.form.Action.{@link #CONNECT_FAILURE}) {
7514 Ext.Msg.alert('Error',
7515 'Status:'+action.{@link #response}.status+': '+
7516 action.{@link #response}.statusText);
7518 if (action.failureType === Ext.form.Action.{@link #SERVER_INVALID}){
7519 // server responded with success = false
7520 Ext.Msg.alert('Invalid', action.{@link #result}.errormsg);
7528 handler: function(){
7529 fp.getForm().reset();
7533 * @property failureType
7537 * The XMLHttpRequest object used to perform the action.
7538 * @property response
7542 * The decoded response object containing a boolean <tt style="font-weight:bold">success</tt> property and
7543 * other, action-specific properties.
7549 run : function(options){
7554 success : function(response){
7559 handleResponse : function(response){
7563 // default connection failure
7564 failure : function(response){
7565 this.response = response;
7566 this.failureType = Ext.form.Action.CONNECT_FAILURE;
7567 this.form.afterAction(this, false);
7571 // shared code among all Actions to validate that there was a response
7572 // with either responseText or responseXml
7573 processResponse : function(response){
7574 this.response = response;
7575 if(!response.responseText && !response.responseXML){
7578 this.result = this.handleResponse(response);
7582 // utility functions used internally
7583 getUrl : function(appendParams){
7584 var url = this.options.url || this.form.url || this.form.el.dom.action;
7586 var p = this.getParams();
7588 url = Ext.urlAppend(url, p);
7595 getMethod : function(){
7596 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7600 getParams : function(){
7601 var bp = this.form.baseParams;
7602 var p = this.options.params;
7604 if(typeof p == "object"){
7605 p = Ext.urlEncode(Ext.applyIf(p, bp));
7606 }else if(typeof p == 'string' && bp){
7607 p += '&' + Ext.urlEncode(bp);
7610 p = Ext.urlEncode(bp);
7616 createCallback : function(opts){
7617 var opts = opts || {};
7619 success: this.success,
7620 failure: this.failure,
7622 timeout: (opts.timeout*1000) || (this.form.timeout*1000),
7623 upload: this.form.fileUpload ? this.success : undefined
7629 * @class Ext.form.Action.Submit
7630 * @extends Ext.form.Action
7631 * <p>A class which handles submission of data from {@link Ext.form.BasicForm Form}s
7632 * and processes the returned response.</p>
7633 * <p>Instances of this class are only created by a {@link Ext.form.BasicForm Form} when
7634 * {@link Ext.form.BasicForm#submit submit}ting.</p>
7635 * <p><u><b>Response Packet Criteria</b></u></p>
7636 * <p>A response packet may contain:
7637 * <div class="mdetail-params"><ul>
7638 * <li><b><code>success</code></b> property : Boolean
7639 * <div class="sub-desc">The <code>success</code> property is required.</div></li>
7640 * <li><b><code>errors</code></b> property : Object
7641 * <div class="sub-desc"><div class="sub-desc">The <code>errors</code> property,
7642 * which is optional, contains error messages for invalid fields.</div></li>
7644 * <p><u><b>JSON Packets</b></u></p>
7645 * <p>By default, response packets are assumed to be JSON, so a typical response
7646 * packet may look like this:</p><pre><code>
7650 clientCode: "Client not found",
7651 portOfLoading: "This field must not be null"
7654 * <p>Other data may be placed into the response for processing by the {@link Ext.form.BasicForm}'s callback
7655 * or event handler methods. The object decoded from this JSON is available in the
7656 * {@link Ext.form.Action#result result} property.</p>
7657 * <p>Alternatively, if an {@link #errorReader} is specified as an {@link Ext.data.XmlReader XmlReader}:</p><pre><code>
7658 errorReader: new Ext.data.XmlReader({
7666 * <p>then the results may be sent back in XML format:</p><pre><code>
7667 <?xml version="1.0" encoding="UTF-8"?>
7668 <message success="false">
7671 <id>clientCode</id>
7672 <msg><![CDATA[Code not found. <br /><i>This is a test validation message from the server </i>]]></msg>
7675 <id>portOfLoading</id>
7676 <msg><![CDATA[Port not found. <br /><i>This is a test validation message from the server </i>]]></msg>
7681 * <p>Other elements may be placed into the response XML for processing by the {@link Ext.form.BasicForm}'s callback
7682 * or event handler methods. The XML document is available in the {@link #errorReader}'s {@link Ext.data.XmlReader#xmlData xmlData} property.</p>
7684 Ext.form.Action.Submit = function(form, options){
7685 Ext.form.Action.Submit.superclass.constructor.call(this, form, options);
7688 Ext.extend(Ext.form.Action.Submit, Ext.form.Action, {
7690 * @cfg {Ext.data.DataReader} errorReader <p><b>Optional. JSON is interpreted with
7691 * no need for an errorReader.</b></p>
7692 * <p>A Reader which reads a single record from the returned data. The DataReader's
7693 * <b>success</b> property specifies how submission success is determined. The Record's
7694 * data provides the error messages to apply to any invalid form Fields.</p>
7697 * @cfg {boolean} clientValidation Determines whether a Form's fields are validated
7698 * in a final call to {@link Ext.form.BasicForm#isValid isValid} prior to submission.
7699 * Pass <tt>false</tt> in the Form's submit options to prevent this. If not defined, pre-submission field validation
7706 var o = this.options;
7707 var method = this.getMethod();
7708 var isGet = method == 'GET';
7709 if(o.clientValidation === false || this.form.isValid()){
7710 Ext.Ajax.request(Ext.apply(this.createCallback(o), {
7711 form:this.form.el.dom,
7712 url:this.getUrl(isGet),
7715 params:!isGet ? this.getParams() : null,
7716 isUpload: this.form.fileUpload
7718 }else if (o.clientValidation !== false){ // client validation failed
7719 this.failureType = Ext.form.Action.CLIENT_INVALID;
7720 this.form.afterAction(this, false);
7725 success : function(response){
7726 var result = this.processResponse(response);
7727 if(result === true || result.success){
7728 this.form.afterAction(this, true);
7732 this.form.markInvalid(result.errors);
7734 this.failureType = Ext.form.Action.SERVER_INVALID;
7735 this.form.afterAction(this, false);
7739 handleResponse : function(response){
7740 if(this.form.errorReader){
7741 var rs = this.form.errorReader.read(response);
7744 for(var i = 0, len = rs.records.length; i < len; i++) {
7745 var r = rs.records[i];
7749 if(errors.length < 1){
7753 success : rs.success,
7757 return Ext.decode(response.responseText);
7763 * @class Ext.form.Action.Load
7764 * @extends Ext.form.Action
7765 * <p>A class which handles loading of data from a server into the Fields of an {@link Ext.form.BasicForm}.</p>
7766 * <p>Instances of this class are only created by a {@link Ext.form.BasicForm Form} when
7767 * {@link Ext.form.BasicForm#load load}ing.</p>
7768 * <p><u><b>Response Packet Criteria</b></u></p>
7769 * <p>A response packet <b>must</b> contain:
7770 * <div class="mdetail-params"><ul>
7771 * <li><b><code>success</code></b> property : Boolean</li>
7772 * <li><b><code>data</code></b> property : Object</li>
7773 * <div class="sub-desc">The <code>data</code> property contains the values of Fields to load.
7774 * The individual value object for each Field is passed to the Field's
7775 * {@link Ext.form.Field#setValue setValue} method.</div></li>
7777 * <p><u><b>JSON Packets</b></u></p>
7778 * <p>By default, response packets are assumed to be JSON, so for the following form load call:<pre><code>
7779 var myFormPanel = new Ext.form.FormPanel({
7780 title: 'Client and routing info',
7782 fieldLabel: 'Client',
7785 fieldLabel: 'Port of loading',
7786 name: 'portOfLoading'
7788 fieldLabel: 'Port of discharge',
7789 name: 'portOfDischarge'
7792 myFormPanel.{@link Ext.form.FormPanel#getForm getForm}().{@link Ext.form.BasicForm#load load}({
7793 url: '/getRoutingInfo.php',
7795 consignmentRef: myConsignmentRef
7797 failure: function(form, action) {
7798 Ext.Msg.alert("Load failed", action.result.errorMessage);
7802 * a <b>success response</b> packet may look like this:</p><pre><code>
7806 clientName: "Fred. Olsen Lines",
7807 portOfLoading: "FXT",
7808 portOfDischarge: "OSL"
7811 * while a <b>failure response</b> packet may look like this:</p><pre><code>
7814 errorMessage: "Consignment reference not found"
7816 * <p>Other data may be placed into the response for processing the {@link Ext.form.BasicForm Form}'s
7817 * callback or event handler methods. The object decoded from this JSON is available in the
7818 * {@link Ext.form.Action#result result} property.</p>
7820 Ext.form.Action.Load = function(form, options){
7821 Ext.form.Action.Load.superclass.constructor.call(this, form, options);
7822 this.reader = this.form.reader;
7825 Ext.extend(Ext.form.Action.Load, Ext.form.Action, {
7831 Ext.Ajax.request(Ext.apply(
7832 this.createCallback(this.options), {
7833 method:this.getMethod(),
7834 url:this.getUrl(false),
7835 headers: this.options.headers,
7836 params:this.getParams()
7841 success : function(response){
7842 var result = this.processResponse(response);
7843 if(result === true || !result.success || !result.data){
7844 this.failureType = Ext.form.Action.LOAD_FAILURE;
7845 this.form.afterAction(this, false);
7848 this.form.clearInvalid();
7849 this.form.setValues(result.data);
7850 this.form.afterAction(this, true);
7854 handleResponse : function(response){
7855 if(this.form.reader){
7856 var rs = this.form.reader.read(response);
7857 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7859 success : rs.success,
7863 return Ext.decode(response.responseText);
7870 * @class Ext.form.Action.DirectLoad
7871 * @extends Ext.form.Action.Load
7872 * <p>Provides Ext.direct support for loading form data.</p>
7873 * <p>This example illustrates usage of Ext.Direct to <b>load</b> a form through Ext.Direct.</p>
7875 var myFormPanel = new Ext.form.FormPanel({
7876 // configs for FormPanel
7877 title: 'Basic Information',
7878 renderTo: document.body,
7879 width: 300, height: 160,
7882 // configs apply to child items
7883 defaults: {anchor: '100%'},
7884 defaultType: 'textfield',
7889 fieldLabel: 'Email',
7892 fieldLabel: 'Company',
7896 // configs for BasicForm
7898 // The server-side method to call for load() requests
7899 load: Profile.getBasicInfo,
7900 // The server-side must mark the submit handler as a 'formHandler'
7901 submit: Profile.updateBasicInfo
7903 // specify the order for the passed params
7904 paramOrder: ['uid', 'foo']
7908 myFormPanel.getForm().load({
7909 // pass 2 arguments to server side getBasicInfo method (len=2)
7916 * The data packet sent to the server will resemble something like:
7920 "action":"Profile","method":"getBasicInfo","type":"rpc","tid":2,
7921 "data":[34,"bar"] // note the order of the params
7925 * The form will process a data packet returned by the server that is similar
7926 * to the following format:
7930 "action":"Profile","method":"getBasicInfo","type":"rpc","tid":2,
7934 "name":"Fred Flintstone",
7935 "company":"Slate Rock and Gravel",
7936 "email":"fred.flintstone@slaterg.com"
7943 Ext.form.Action.DirectLoad = Ext.extend(Ext.form.Action.Load, {
7944 constructor: function(form, opts) {
7945 Ext.form.Action.DirectLoad.superclass.constructor.call(this, form, opts);
7947 type : 'directload',
7950 var args = this.getParams();
7951 args.push(this.success, this);
7952 this.form.api.load.apply(window, args);
7955 getParams : function() {
7956 var buf = [], o = {};
7957 var bp = this.form.baseParams;
7958 var p = this.options.params;
7959 Ext.apply(o, p, bp);
7960 var paramOrder = this.form.paramOrder;
7962 for(var i = 0, len = paramOrder.length; i < len; i++){
7963 buf.push(o[paramOrder[i]]);
7965 }else if(this.form.paramsAsHash){
7970 // Direct actions have already been processed and therefore
7971 // we can directly set the result; Direct Actions do not have
7972 // a this.response property.
7973 processResponse : function(result) {
7974 this.result = result;
7978 success : function(response, trans){
7979 if(trans.type == Ext.Direct.exceptions.SERVER){
7982 Ext.form.Action.DirectLoad.superclass.success.call(this, response);
7987 * @class Ext.form.Action.DirectSubmit
7988 * @extends Ext.form.Action.Submit
7989 * <p>Provides Ext.direct support for submitting form data.</p>
7990 * <p>This example illustrates usage of Ext.Direct to <b>submit</b> a form through Ext.Direct.</p>
7992 var myFormPanel = new Ext.form.FormPanel({
7993 // configs for FormPanel
7994 title: 'Basic Information',
7995 renderTo: document.body,
7996 width: 300, height: 160,
8000 handler: function(){
8001 myFormPanel.getForm().submit({
8010 // configs apply to child items
8011 defaults: {anchor: '100%'},
8012 defaultType: 'textfield',
8017 fieldLabel: 'Email',
8020 fieldLabel: 'Company',
8024 // configs for BasicForm
8026 // The server-side method to call for load() requests
8027 load: Profile.getBasicInfo,
8028 // The server-side must mark the submit handler as a 'formHandler'
8029 submit: Profile.updateBasicInfo
8031 // specify the order for the passed params
8032 paramOrder: ['uid', 'foo']
8035 * The data packet sent to the server will resemble something like:
8038 "action":"Profile","method":"updateBasicInfo","type":"rpc","tid":"6",
8042 "extAction":"Profile","extMethod":"updateBasicInfo",
8043 "extType":"rpc","extTID":"6","extUpload":"false",
8044 "name":"Aaron Conran","email":"aaron@extjs.com","company":"Ext JS, LLC"
8049 * The form will process a data packet returned by the server that is similar
8052 // sample success packet (batched requests)
8055 "action":"Profile","method":"updateBasicInfo","type":"rpc","tid":3,
8062 // sample failure packet (one request)
8064 "action":"Profile","method":"updateBasicInfo","type":"rpc","tid":"6",
8067 "email":"already taken"
8074 * Also see the discussion in {@link Ext.form.Action.DirectLoad}.
8076 Ext.form.Action.DirectSubmit = Ext.extend(Ext.form.Action.Submit, {
8077 constructor : function(form, opts) {
8078 Ext.form.Action.DirectSubmit.superclass.constructor.call(this, form, opts);
8080 type : 'directsubmit',
8081 // override of Submit
8083 var o = this.options;
8084 if(o.clientValidation === false || this.form.isValid()){
8085 // tag on any additional params to be posted in the
8087 this.success.params = this.getParams();
8088 this.form.api.submit(this.form.el.dom, this.success, this);
8089 }else if (o.clientValidation !== false){ // client validation failed
8090 this.failureType = Ext.form.Action.CLIENT_INVALID;
8091 this.form.afterAction(this, false);
8095 getParams : function() {
8097 var bp = this.form.baseParams;
8098 var p = this.options.params;
8099 Ext.apply(o, p, bp);
8102 // Direct actions have already been processed and therefore
8103 // we can directly set the result; Direct Actions do not have
8104 // a this.response property.
8105 processResponse : function(result) {
8106 this.result = result;
8110 success : function(response, trans){
8111 if(trans.type == Ext.Direct.exceptions.SERVER){
8114 Ext.form.Action.DirectSubmit.superclass.success.call(this, response);
8118 Ext.form.Action.ACTION_TYPES = {
8119 'load' : Ext.form.Action.Load,
8120 'submit' : Ext.form.Action.Submit,
8121 'directload' : Ext.form.Action.DirectLoad,
8122 'directsubmit' : Ext.form.Action.DirectSubmit
8125 * @class Ext.form.VTypes
8126 * <p>This is a singleton object which contains a set of commonly used field validation functions.
8127 * The validations provided are basic and intended to be easily customizable and extended.</p>
8128 * <p>To add custom VTypes specify the <code>{@link Ext.form.TextField#vtype vtype}</code> validation
8129 * test function, and optionally specify any corresponding error text to display and any keystroke
8130 * filtering mask to apply. For example:</p>
8132 // custom Vtype for vtype:'time'
8133 var timeTest = /^([1-9]|1[0-9]):([0-5][0-9])(\s[a|p]m)$/i;
8134 Ext.apply(Ext.form.VTypes, {
8135 // vtype validation function
8136 time: function(val, field) {
8137 return timeTest.test(val);
8139 // vtype Text property: The error text to display when the validation function returns false
8140 timeText: 'Not a valid time. Must be in the format "12:34 PM".',
8141 // vtype Mask property: The keystroke filter mask
8142 timeMask: /[\d\s:amp]/i
8147 // custom Vtype for vtype:'IPAddress'
8148 Ext.apply(Ext.form.VTypes, {
8149 IPAddress: function(v) {
8150 return /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(v);
8152 IPAddressText: 'Must be a numeric IP address',
8153 IPAddressMask: /[\d\.]/i
8158 Ext.form.VTypes = function(){
8159 // closure these in so they are only created once.
8160 var alpha = /^[a-zA-Z_]+$/,
8161 alphanum = /^[a-zA-Z0-9_]+$/,
8162 email = /^(\w+)([\-+.][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z]){2,6}$/,
8163 url = /(((^https?)|(^ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8165 // All these messages and functions are configurable
8168 * The function used to validate email addresses. Note that this is a very basic validation -- complete
8169 * validation per the email RFC specifications is very complex and beyond the scope of this class, although
8170 * this function can be overridden if a more comprehensive validation scheme is desired. See the validation
8171 * section of the <a href="http://en.wikipedia.org/wiki/E-mail_address">Wikipedia article on email addresses</a>
8172 * for additional information. This implementation is intended to validate the following emails:<tt>
8173 * 'barney@example.de', 'barney.rubble@example.com', 'barney-rubble@example.coop', 'barney+rubble@example.com'
8175 * @param {String} value The email address
8176 * @return {Boolean} true if the RegExp test passed, and false if not.
8178 'email' : function(v){
8179 return email.test(v);
8182 * The error text to display when the email validation function returns false. Defaults to:
8183 * <tt>'This field should be an e-mail address in the format "user@example.com"'</tt>
8186 'emailText' : 'This field should be an e-mail address in the format "user@example.com"',
8188 * The keystroke filter mask to be applied on email input. See the {@link #email} method for
8189 * information about more complex email validation. Defaults to:
8190 * <tt>/[a-z0-9_\.\-@]/i</tt>
8193 'emailMask' : /[a-z0-9_\.\-@]/i,
8196 * The function used to validate URLs
8197 * @param {String} value The URL
8198 * @return {Boolean} true if the RegExp test passed, and false if not.
8200 'url' : function(v){
8204 * The error text to display when the url validation function returns false. Defaults to:
8205 * <tt>'This field should be a URL in the format "http:/'+'/www.example.com"'</tt>
8208 'urlText' : 'This field should be a URL in the format "http:/'+'/www.example.com"',
8211 * The function used to validate alpha values
8212 * @param {String} value The value
8213 * @return {Boolean} true if the RegExp test passed, and false if not.
8215 'alpha' : function(v){
8216 return alpha.test(v);
8219 * The error text to display when the alpha validation function returns false. Defaults to:
8220 * <tt>'This field should only contain letters and _'</tt>
8223 'alphaText' : 'This field should only contain letters and _',
8225 * The keystroke filter mask to be applied on alpha input. Defaults to:
8226 * <tt>/[a-z_]/i</tt>
8229 'alphaMask' : /[a-z_]/i,
8232 * The function used to validate alphanumeric values
8233 * @param {String} value The value
8234 * @return {Boolean} true if the RegExp test passed, and false if not.
8236 'alphanum' : function(v){
8237 return alphanum.test(v);
8240 * The error text to display when the alphanumeric validation function returns false. Defaults to:
8241 * <tt>'This field should only contain letters, numbers and _'</tt>
8244 'alphanumText' : 'This field should only contain letters, numbers and _',
8246 * The keystroke filter mask to be applied on alphanumeric input. Defaults to:
8247 * <tt>/[a-z0-9_]/i</tt>
8250 'alphanumMask' : /[a-z0-9_]/i