X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/6746dc89c47ed01b165cc1152533605f97eb8e8d..HEAD:/src/form/field/Field.js diff --git a/src/form/field/Field.js b/src/form/field/Field.js index d2d18d4d..9065374b 100644 --- a/src/form/field/Field.js +++ b/src/form/field/Field.js @@ -13,69 +13,70 @@ If you are unsure which license is appropriate for your use, please contact the */ /** - * @class Ext.form.field.Field - -This mixin provides a common interface for the logical behavior and state of form fields, including: - -- Getter and setter methods for field values -- Events and methods for tracking value and validity changes -- Methods for triggering validation - -**NOTE**: When implementing custom fields, it is most likely that you will want to extend the {@link Ext.form.field.Base} -component class rather than using this mixin directly, as BaseField contains additional logic for generating an -actual DOM complete with {@link Ext.form.Labelable label and error message} display and a form input field, -plus methods that bind the Field value getters and setters to the input field's value. - -If you do want to implement this mixin directly and don't want to extend {@link Ext.form.field.Base}, then -you will most likely want to override the following methods with custom implementations: {@link #getValue}, -{@link #setValue}, and {@link #getErrors}. Other methods may be overridden as needed but their base -implementations should be sufficient for common cases. You will also need to make sure that {@link #initField} -is called during the component's initialization. - - * @markdown * @docauthor Jason Johnston + * + * This mixin provides a common interface for the logical behavior and state of form fields, including: + * + * - Getter and setter methods for field values + * - Events and methods for tracking value and validity changes + * - Methods for triggering validation + * + * **NOTE**: When implementing custom fields, it is most likely that you will want to extend the {@link Ext.form.field.Base} + * component class rather than using this mixin directly, as BaseField contains additional logic for generating an + * actual DOM complete with {@link Ext.form.Labelable label and error message} display and a form input field, + * plus methods that bind the Field value getters and setters to the input field's value. + * + * If you do want to implement this mixin directly and don't want to extend {@link Ext.form.field.Base}, then + * you will most likely want to override the following methods with custom implementations: {@link #getValue}, + * {@link #setValue}, and {@link #getErrors}. Other methods may be overridden as needed but their base + * implementations should be sufficient for common cases. You will also need to make sure that {@link #initField} + * is called during the component's initialization. */ Ext.define('Ext.form.field.Field', { - /** - * @property isFormField - * @type {Boolean} + * @property {Boolean} isFormField * Flag denoting that this component is a Field. Always true. */ isFormField : true, /** - * @cfg {Mixed} value A value to initialize this field with (defaults to undefined). + * @cfg {Object} value + * A value to initialize this field with. */ - + /** - * @cfg {String} name The name of the field (defaults to undefined). By default this is used as the parameter - * name when including the {@link #getSubmitData field value} in a {@link Ext.form.Basic#submit form submit()}. - * To prevent the field from being included in the form submit, set {@link #submitValue} to false. + * @cfg {String} name + * The name of the field. By default this is used as the parameter name when including the + * {@link #getSubmitData field value} in a {@link Ext.form.Basic#submit form submit()}. To prevent the field from + * being included in the form submit, set {@link #submitValue} to false. */ /** - * @cfg {Boolean} disabled True to disable the field (defaults to false). Disabled Fields will not be - * {@link Ext.form.Basic#submit submitted}.

+ * @cfg {Boolean} disabled + * True to disable the field. Disabled Fields will not be {@link Ext.form.Basic#submit submitted}. */ disabled : false, /** - * @cfg {Boolean} submitValue Setting this to false will prevent the field from being - * {@link Ext.form.Basic#submit submitted} even when it is not disabled. Defaults to true. + * @cfg {Boolean} submitValue + * Setting this to false will prevent the field from being {@link Ext.form.Basic#submit submitted} even when it is + * not disabled. */ submitValue: true, /** * @cfg {Boolean} validateOnChange - *

Specifies whether this field should be validated immediately whenever a change in its value is detected. - * Defaults to true. If the validation results in a change in the field's validity, a - * {@link #validitychange} event will be fired. This allows the field to show feedback about the - * validity of its contents immediately as the user is typing.

- *

When set to false, feedback will not be immediate. However the form will still be validated - * before submitting if the clientValidation option to {@link Ext.form.Basic#doAction} is - * enabled, or if the field or form are validated manually.

- *

See also {@link Ext.form.field.Base#checkChangeEvents}for controlling how changes to the field's value are detected.

+ * Specifies whether this field should be validated immediately whenever a change in its value is detected. + * If the validation results in a change in the field's validity, a {@link #validitychange} event will be + * fired. This allows the field to show feedback about the validity of its contents immediately as the user is + * typing. + * + * When set to false, feedback will not be immediate. However the form will still be validated before submitting if + * the clientValidation option to {@link Ext.form.Basic#doAction} is enabled, or if the field or form are validated + * manually. + * + * See also {@link Ext.form.field.Base#checkChangeEvents} for controlling how changes to the field's value are + * detected. */ validateOnChange: true, @@ -85,8 +86,8 @@ Ext.define('Ext.form.field.Field', { suspendCheckChange: 0, /** - * Initializes this Field mixin on the current instance. Components using this mixin should call - * this method during their own initialization process. + * Initializes this Field mixin on the current instance. Components using this mixin should call this method during + * their own initialization process. */ initField: function() { this.addEvents( @@ -94,8 +95,8 @@ Ext.define('Ext.form.field.Field', { * @event change * Fires when a user-initiated change is detected in the value of the field. * @param {Ext.form.field.Field} this - * @param {Mixed} newValue The new value - * @param {Mixed} oldValue The original value + * @param {Object} newValue The new value + * @param {Object} oldValue The original value */ 'change', /** @@ -118,18 +119,15 @@ Ext.define('Ext.form.field.Field', { }, /** - * @protected * Initializes the field's value based on the initial config. */ initValue: function() { var me = this; /** - * @property originalValue - * @type Mixed - * The original value of the field as configured in the {@link #value} configuration, or as loaded by - * the last form load operation if the form's {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad} - * setting is true. + * @property {Object} originalValue + * The original value of the field as configured in the {@link #value} configuration, or as loaded by the last + * form load operation if the form's {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad} setting is `true`. */ me.originalValue = me.lastValue = me.value; @@ -140,8 +138,8 @@ Ext.define('Ext.form.field.Field', { }, /** - * Returns the {@link Ext.form.field.Field#name name} attribute of the field. This is used as the parameter - * name when including the field value in a {@link Ext.form.Basic#submit form submit()}. + * Returns the {@link Ext.form.field.Field#name name} attribute of the field. This is used as the parameter name + * when including the field value in a {@link Ext.form.Basic#submit form submit()}. * @return {String} name The field {@link Ext.form.field.Field#name name} */ getName: function() { @@ -151,15 +149,15 @@ Ext.define('Ext.form.field.Field', { /** * Returns the current data value of the field. The type of value returned is particular to the type of the * particular field (e.g. a Date object for {@link Ext.form.field.Date}). - * @return {Mixed} value The field value + * @return {Object} value The field value */ getValue: function() { return this.value; }, - + /** * Sets a data value into the field and runs the change detection and validation. - * @param {Mixed} value The value to set + * @param {Object} value The value to set * @return {Ext.form.field.Field} this */ setValue: function(value) { @@ -170,26 +168,39 @@ Ext.define('Ext.form.field.Field', { }, /** - * Returns whether two field {@link #getValue values} are logically equal. Field implementations may override - * this to provide custom comparison logic appropriate for the particular field's data type. - * @param {Mixed} value1 The first value to compare - * @param {Mixed} value2 The second value to compare + * Returns whether two field {@link #getValue values} are logically equal. Field implementations may override this + * to provide custom comparison logic appropriate for the particular field's data type. + * @param {Object} value1 The first value to compare + * @param {Object} value2 The second value to compare * @return {Boolean} True if the values are equal, false if inequal. */ isEqual: function(value1, value2) { return String(value1) === String(value2); }, + + /** + * Returns whether two values are logically equal. + * Similar to {@link #isEqual}, however null or undefined values will be treated as empty strings. + * @private + * @param {Object} value1 The first value to compare + * @param {Object} value2 The second value to compare + * @return {Boolean} True if the values are equal, false if inequal. + */ + isEqualAsString: function(value1, value2){ + return String(Ext.value(value1, '')) === String(Ext.value(value2, '')); + }, /** - *

Returns the parameter(s) that would be included in a standard form submit for this field. Typically this - * will be an object with a single name-value pair, the name being this field's {@link #getName name} and the - * value being its current stringified value. More advanced field implementations may return more than one - * name-value pair.

- *

Note that the values returned from this method are not guaranteed to have been successfully - * {@link #validate validated}.

- * @return {Object} A mapping of submit parameter names to values; each value should be a string, or an array - * of strings if that particular name has multiple values. It can also return null if there are no - * parameters to be submitted. + * Returns the parameter(s) that would be included in a standard form submit for this field. Typically this will be + * an object with a single name-value pair, the name being this field's {@link #getName name} and the value being + * its current stringified value. More advanced field implementations may return more than one name-value pair. + * + * Note that the values returned from this method are not guaranteed to have been successfully {@link #validate + * validated}. + * + * @return {Object} A mapping of submit parameter names to values; each value should be a string, or an array of + * strings if that particular name has multiple values. It can also return null if there are no parameters to be + * submitted. */ getSubmitData: function() { var me = this, @@ -202,16 +213,18 @@ Ext.define('Ext.form.field.Field', { }, /** - *

Returns the value(s) that should be saved to the {@link Ext.data.Model} instance for this field, when - * {@link Ext.form.Basic#updateRecord} is called. Typically this will be an object with a single name-value - * pair, the name being this field's {@link #getName name} and the value being its current data value. More - * advanced field implementations may return more than one name-value pair. The returned values will be - * saved to the corresponding field names in the Model.

- *

Note that the values returned from this method are not guaranteed to have been successfully - * {@link #validate validated}.

- * @return {Object} A mapping of submit parameter names to values; each value should be a string, or an array - * of strings if that particular name has multiple values. It can also return null if there are no - * parameters to be submitted. + * Returns the value(s) that should be saved to the {@link Ext.data.Model} instance for this field, when {@link + * Ext.form.Basic#updateRecord} is called. Typically this will be an object with a single name-value pair, the name + * being this field's {@link #getName name} and the value being its current data value. More advanced field + * implementations may return more than one name-value pair. The returned values will be saved to the corresponding + * field names in the Model. + * + * Note that the values returned from this method are not guaranteed to have been successfully {@link #validate + * validated}. + * + * @return {Object} A mapping of submit parameter names to values; each value should be a string, or an array of + * strings if that particular name has multiple values. It can also return null if there are no parameters to be + * submitted. */ getModelData: function() { var me = this, @@ -224,12 +237,12 @@ Ext.define('Ext.form.field.Field', { }, /** - * Resets the current field value to the originally loaded value and clears any validation messages. - * See {@link Ext.form.Basic}.{@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad} + * Resets the current field value to the originally loaded value and clears any validation messages. See {@link + * Ext.form.Basic}.{@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad} */ reset : function(){ var me = this; - + me.setValue(me.originalValue); me.clearInvalid(); // delete here so we reset back to the original state @@ -237,8 +250,8 @@ Ext.define('Ext.form.field.Field', { }, /** - * Resets the field's {@link #originalValue} property so it matches the current {@link #getValue value}. - * This is called by {@link Ext.form.Basic}.{@link Ext.form.Basic#setValues setValues} if the form's + * Resets the field's {@link #originalValue} property so it matches the current {@link #getValue value}. This is + * called by {@link Ext.form.Basic}.{@link Ext.form.Basic#setValues setValues} if the form's * {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad} property is set to true. */ resetOriginalValue: function() { @@ -247,15 +260,14 @@ Ext.define('Ext.form.field.Field', { }, /** - *

Checks whether the value of the field has changed since the last time it was checked. If the value - * has changed, it:

- *
    - *
  1. Fires the {@link #change change event},
  2. - *
  3. Performs validation if the {@link #validateOnChange} config is enabled, firing the - * {@link #validationchange validationchange event} if the validity has changed, and
  4. - *
  5. Checks the {@link #isDirty dirty state} of the field and fires the {@link #dirtychange dirtychange event} - * if it has changed.
  6. - *
+ * Checks whether the value of the field has changed since the last time it was checked. + * If the value has changed, it: + * + * 1. Fires the {@link #change change event}, + * 2. Performs validation if the {@link #validateOnChange} config is enabled, firing the + * {@link #validitychange validitychange event} if the validity has changed, and + * 3. Checks the {@link #isDirty dirty state} of the field and fires the {@link #dirtychange dirtychange event} + * if it has changed. */ checkChange: function() { if (!this.suspendCheckChange) { @@ -283,14 +295,14 @@ Ext.define('Ext.form.field.Field', { }, /** - *

Returns true if the value of this Field has been changed from its {@link #originalValue}. - * Will always return false if the field is disabled.

- *

Note that if the owning {@link Ext.form.Basic form} was configured with - * {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad} - * then the {@link #originalValue} is updated when the values are loaded by - * {@link Ext.form.Basic}.{@link Ext.form.Basic#setValues setValues}.

- * @return {Boolean} True if this field has been changed from its original value (and - * is not disabled), false otherwise. + * Returns true if the value of this Field has been changed from its {@link #originalValue}. + * Will always return false if the field is disabled. + * + * Note that if the owning {@link Ext.form.Basic form} was configured with + * {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad} then the {@link #originalValue} is updated when + * the values are loaded by {@link Ext.form.Basic}.{@link Ext.form.Basic#setValues setValues}. + * @return {Boolean} True if this field has been changed from its original value (and is not disabled), + * false otherwise. */ isDirty : function() { var me = this; @@ -298,8 +310,8 @@ Ext.define('Ext.form.field.Field', { }, /** - * Checks the {@link #isDirty} state of the field and if it has changed since the last time - * it was checked, fires the {@link #dirtychange} event. + * Checks the {@link #isDirty} state of the field and if it has changed since the last time it was checked, + * fires the {@link #dirtychange} event. */ checkDirty: function() { var me = this, @@ -318,22 +330,26 @@ Ext.define('Ext.form.field.Field', { onDirtyChange: Ext.emptyFn, /** - *

Runs this field's validators and returns an array of error messages for any validation failures. - * This is called internally during validation and would not usually need to be used manually.

- *

Each subclass should override or augment the return value to provide their own errors.

- * @param {Mixed} value The value to get errors for (defaults to the current field value) - * @return {Array} All error messages for this field; an empty Array if none. + * Runs this field's validators and returns an array of error messages for any validation failures. This is called + * internally during validation and would not usually need to be used manually. + * + * Each subclass should override or augment the return value to provide their own errors. + * + * @param {Object} value The value to get errors for (defaults to the current field value) + * @return {String[]} All error messages for this field; an empty Array if none. */ getErrors: function(value) { return []; }, /** - *

Returns whether or not the field value is currently valid by {@link #getErrors validating} the - * field's current value. The {@link #validitychange} event will not be fired; use {@link #validate} - * instead if you want the event to fire. Note: {@link #disabled} fields are always treated as valid.

- *

Implementations are encouraged to ensure that this method does not have side-effects such as - * triggering error message display.

+ * Returns whether or not the field value is currently valid by {@link #getErrors validating} the field's current + * value. The {@link #validitychange} event will not be fired; use {@link #validate} instead if you want the event + * to fire. **Note**: {@link #disabled} fields are always treated as valid. + * + * Implementations are encouraged to ensure that this method does not have side-effects such as triggering error + * message display. + * * @return {Boolean} True if the value is valid, else false */ isValid : function() { @@ -342,11 +358,13 @@ Ext.define('Ext.form.field.Field', { }, /** - *

Returns whether or not the field value is currently valid by {@link #getErrors validating} the - * field's current value, and fires the {@link #validitychange} event if the field's validity has - * changed since the last validation. Note: {@link #disabled} fields are always treated as valid.

- *

Custom implementations of this method are allowed to have side-effects such as triggering error - * message display. To validate without side-effects, use {@link #isValid}.

+ * Returns whether or not the field value is currently valid by {@link #getErrors validating} the field's current + * value, and fires the {@link #validitychange} event if the field's validity has changed since the last validation. + * **Note**: {@link #disabled} fields are always treated as valid. + * + * Custom implementations of this method are allowed to have side-effects such as triggering error message display. + * To validate without side-effects, use {@link #isValid}. + * * @return {Boolean} True if the value is valid, else false */ validate : function() { @@ -360,24 +378,29 @@ Ext.define('Ext.form.field.Field', { }, /** - * A utility for grouping a set of modifications which may trigger value changes into a single - * transaction, to prevent excessive firing of {@link #change} events. This is useful for instance - * if the field has sub-fields which are being updated as a group; you don't want the container - * field to check its own changed state for each subfield change. - * @param fn A function containing the transaction code + * A utility for grouping a set of modifications which may trigger value changes into a single transaction, to + * prevent excessive firing of {@link #change} events. This is useful for instance if the field has sub-fields which + * are being updated as a group; you don't want the container field to check its own changed state for each subfield + * change. + * @param {Object} fn A function containing the transaction code */ batchChanges: function(fn) { - this.suspendCheckChange++; - fn(); - this.suspendCheckChange--; + try { + this.suspendCheckChange++; + fn(); + } catch(e){ + throw e; + } finally { + this.suspendCheckChange--; + } this.checkChange(); }, /** - * Returns whether this Field is a file upload field; if it returns true, forms will use - * special techniques for {@link Ext.form.Basic#submit submitting the form} via AJAX. See - * {@link Ext.form.Basic#hasUpload} for details. If this returns true, the {@link #extractFileInput} - * method must also be implemented to return the corresponding file input element. + * Returns whether this Field is a file upload field; if it returns true, forms will use special techniques for + * {@link Ext.form.Basic#submit submitting the form} via AJAX. See {@link Ext.form.Basic#hasUpload} for details. If + * this returns true, the {@link #extractFileInput} method must also be implemented to return the corresponding file + * input element. * @return {Boolean} */ isFileUpload: function() { @@ -385,35 +408,36 @@ Ext.define('Ext.form.field.Field', { }, /** - * Only relevant if the instance's {@link #isFileUpload} method returns true. Returns a reference - * to the file input DOM element holding the user's selected file. The input will be appended into - * the submission form and will not be returned, so this method should also create a replacement. - * @return {HTMLInputElement} + * Only relevant if the instance's {@link #isFileUpload} method returns true. Returns a reference to the file input + * DOM element holding the user's selected file. The input will be appended into the submission form and will not be + * returned, so this method should also create a replacement. + * @return {HTMLElement} */ extractFileInput: function() { return null; }, /** - *

Associate one or more error messages with this field. Components using this mixin should implement - * this method to update the component's rendering to display the messages.

- *

Note: this method does not cause the Field's {@link #validate} or {@link #isValid} methods to - * return false if the value does pass validation. So simply marking a Field as invalid - * will not prevent submission of forms submitted with the {@link Ext.form.action.Submit#clientValidation} - * option set.

- * @param {String/Array} errors The error message(s) for the field. - * @method + * @method markInvalid + * Associate one or more error messages with this field. Components using this mixin should implement this method to + * update the component's rendering to display the messages. + * + * **Note**: this method does not cause the Field's {@link #validate} or {@link #isValid} methods to return `false` + * if the value does _pass_ validation. So simply marking a Field as invalid will not prevent submission of forms + * submitted with the {@link Ext.form.action.Submit#clientValidation} option set. + * + * @param {String/String[]} errors The error message(s) for the field. */ markInvalid: Ext.emptyFn, /** - *

Clear any invalid styles/messages for this field. Components using this mixin should implement - * this method to update the components rendering to clear any existing messages.

- *

Note: this method does not cause the Field's {@link #validate} or {@link #isValid} methods to - * return true if the value does not pass validation. So simply clearing a field's errors - * will not necessarily allow submission of forms submitted with the {@link Ext.form.action.Submit#clientValidation} - * option set.

- * @method + * @method clearInvalid + * Clear any invalid styles/messages for this field. Components using this mixin should implement this method to + * update the components rendering to clear any existing messages. + * + * **Note**: this method does not cause the Field's {@link #validate} or {@link #isValid} methods to return `true` + * if the value does not _pass_ validation. So simply clearing a field's errors will not necessarily allow + * submission of forms submitted with the {@link Ext.form.action.Submit#clientValidation} option set. */ clearInvalid: Ext.emptyFn