/*
* Ext GWT 2.2.4 - Ext for GWT
* Copyright(c) 2007-2010, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
package com.extjs.gxt.ui.client.widget.form;
import com.extjs.gxt.ui.client.GXT;
import com.extjs.gxt.ui.client.Style.HideMode;
import com.extjs.gxt.ui.client.core.El;
import com.extjs.gxt.ui.client.core.XDOM;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.FieldEvent;
import com.extjs.gxt.ui.client.event.KeyListener;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.util.DelayedTask;
import com.extjs.gxt.ui.client.util.Format;
import com.extjs.gxt.ui.client.util.KeyNav;
import com.extjs.gxt.ui.client.util.Util;
import com.extjs.gxt.ui.client.widget.BoxComponent;
import com.extjs.gxt.ui.client.widget.ComponentHelper;
import com.extjs.gxt.ui.client.widget.WidgetComponent;
import com.extjs.gxt.ui.client.widget.layout.FormLayout;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
/**
* Base class for form fields that provides default event handling, value
* handling and other functionality.
*
* <dl>
* <dt><b>Events:</b></dt>
* <dd><b>Focus</b> : FieldEvent(field)<br>
* <div>Fires when this field receives input focus.</div>
* <ul>
* <li>field : this</li>
* </ul>
* </dd>
* <dd><b>Blur</b> : FieldEvent(field)<br>
* <div>Fires when this field loses input focus.</div>
* <ul>
* <li>field : this</li>
* </ul>
* </dd>
* <dd><b>Change</b> : FieldEvent(field, value, oldValue)<br>
* <div>Fires after the field's value is changed.</div>
* <ul>
* <li>field : this</li>
* <li>value : the new value</li>
* <li>oldValue : the old value</li>
* </ul>
* </dd>
* <dd><b>Invalid</b> : FieldEvent(field, message)<br>
* <div>Fires after the field has been marked as invalid.</div>
* <ul>
* <li>field : this</li>
* <li>message : the validation message</li>
* </ul>
* </dd>
* <dd><b>Valid</b> : FieldEvent(field)<br>
* <div>Fires after the field has been validated with no errors.</div>
* <ul>
* <li>field : this</li>
* </ul>
* </dd>
* <dd><b>KeyPress</b> : FieldEvent(field)<br>
* <div>Fires after a key is pressed.</div>
* <ul>
* <li>field : this</li>
* </ul>
* </dd>
* <dd><b>SpecialKey</b> : FieldEvent(field)<br>
* <div>Fires when any key related to navigation (arrows, tab, enter, esc, etc.)
* is pressed.</div>
* <ul>
* <li>field : this</li>
* </ul>
* </dd>
* </dl>
*
* <dl>
* <dt>Inherited Events:</dt>
* <dd>BoxComponent Move</dd>
* <dd>BoxComponent Resize</dd>
* <dd>Component Enable</dd>
* <dd>Component Disable</dd>
* <dd>Component BeforeHide</dd>
* <dd>Component Hide</dd>
* <dd>Component BeforeShow</dd>
* <dd>Component Show</dd>
* <dd>Component Attach</dd>
* <dd>Component Detach</dd>
* <dd>Component BeforeRender</dd>
* <dd>Component Render</dd>
* <dd>Component BrowserEvent</dd>
* <dd>Component BeforeStateRestore</dd>
* <dd>Component StateRestore</dd>
* <dd>Component BeforeStateSave</dd>
* <dd>Component SaveState</dd>
* </dl>
*
* @param <D> the data type of the field
*/
@SuppressWarnings("deprecation")
public abstract class Field<D> extends BoxComponent {
public class FieldImages {
private AbstractImagePrototype invalid = GXT.IMAGES.field_invalid();
public AbstractImagePrototype getInvalid() {
return invalid;
}
public void setInvalid(AbstractImagePrototype invalid) {
this.invalid = invalid;
}
}
/**
* The field messages.
*/
public class FieldMessages {
private String invalidText = GXT.MESSAGES.field_invalidText();
/**
* Returns the invalid text.
*
* @return the text
*/
public String getInvalidText() {
return invalidText;
}
/**
* Sets the error text to use when marking a field invalid and no message is
* provided (defaults to "The value in this field is invalid").
*
* @param invalidText the invalid text
*/
public void setInvalidText(String invalidText) {
this.invalidText = invalidText;
}
}
protected boolean autoValidate;
protected String emptyText;
protected WidgetComponent errorIcon;
protected String fieldStyle = "x-form-field";
protected String focusStyle = "x-form-focus";
protected Object focusValue;
protected String forceInvalidText;
protected boolean hasFocus;
protected FieldImages images;
protected String invalidStyle = "x-form-invalid";
protected FieldMessages messages;
protected String name;
protected D originalValue;
protected boolean preventMark;
protected PropertyEditor<D> propertyEditor;
protected boolean readOnly;
protected String readOnlyFieldStyle = "x-form-readonly";
protected int validationDelay = 250;
protected DelayedTask validationTask;
protected D value;
private String activeErrorMessage;
private String fieldLabel = "";
private boolean fireChangeEventOnSetValue;
private boolean hideLabel;
private boolean inEditor;
private String inputStyle;
private String inputStyles = "";
private String labelSeparator;
private String labelStyle = "";
private String messageTarget = "side";
private int tabIndex = 0;
private boolean validateOnBlur = true;
/**
* Creates a new field.
*/
@SuppressWarnings("unchecked")
protected Field() {
propertyEditor = (PropertyEditor<D>) PropertyEditor.DEFAULT;
messages = new FieldMessages();
}
/**
* Adds a CSS style name to the input element of this field.
*
* @param style the style name
*/
public void addInputStyleName(String style) {
if (rendered) {
El inputEl = getInputEl();
if (inputEl != null) {
inputEl.addStyleName(style);
}
} else {
inputStyle = inputStyle == null ? style : inputStyle + " " + style;
}
}
/**
* Adds a key listener.
*
* @param listener the key listener
*/
public void addKeyListener(KeyListener listener) {
addListener(Events.KeyPress, listener);
addListener(Events.KeyUp, listener);
addListener(Events.KeyDown, listener);
}
/**
* Clears the value from the field.
*/
public void clear() {
boolean restore = preventMark;
preventMark = true;
setValue(null);
preventMark = restore;
clearInvalid();
}
/**
* Clear any invalid styles / messages for this field.
*/
public void clearInvalid() {
if (!rendered) {
return;
}
getInputEl().removeStyleName(invalidStyle);
if (forceInvalidText != null) {
forceInvalidText = null;
}
if ("side".equals(messageTarget)) {
if (errorIcon != null && errorIcon.isAttached()) {
ComponentHelper.doDetach(errorIcon);
errorIcon.setVisible(false);
setAriaState("aria-describedby", "");
}
} else if ("title".equals(messageTarget)) {
setTitle("");
} else if ("tooltip".equals(messageTarget)) {
hideToolTip();
if (toolTip != null) {
toolTip.disable();
}
} else {
Element elem = XDOM.getElementById(messageTarget);
if (elem != null) {
elem.setInnerHTML("");
}
}
if (GXT.isAriaEnabled()) {
getAriaSupport().setState("aria-invalid", "false");
}
fireEvent(Events.Valid, new FieldEvent(this));
}
@Override
public void focus() {
super.focus();
if (rendered) {
onFocus(new FieldEvent(this));
}
}
/**
* Forces the field to be invalid using the given error message. When using
* this feature, {@link #clearInvalid()} must be called to clear the error.
* Also, no other validation logic will execute.
*
* @param msg the error text
*/
public void forceInvalid(String msg) {
forceInvalidText = msg;
markInvalid(msg);
}
/**
* Returns true if the field value is validated on each key press.
*
* @return the auto validate state
*/
public boolean getAutoValidate() {
return autoValidate;
}
/**
* Returns the field's empty text.
*
* @return the empty text
*/
public String getEmptyText() {
return emptyText;
}
/**
* Returns the active error message as string
*
* @return the active error message
*/
public String getErrorMessage() {
return activeErrorMessage;
}
/**
* Returns the field's label.
*
* @return the label
*/
public String getFieldLabel() {
return fieldLabel;
}
public FieldImages getImages() {
if (images == null) {
images = new FieldImages();
}
return images;
}
/**
* Returns the field's label separator.
*
* @return the label separator
*/
public String getLabelSeparator() {
return labelSeparator;
}
/**
* Returns the field's label style.
*
* @return the label style
*/
public String getLabelStyle() {
return labelStyle;
}
/**
* Returns the field's messages.
*
* @return the messages
*/
public FieldMessages getMessages() {
return messages;
}
/**
* Returns the field's message target.
*
* @return the message target
*/
public String getMessageTarget() {
return messageTarget;
}
/**
* Returns the name attribute of the field if available.
*
* @return the field name
*/
public String getName() {
if (rendered) {
String n = getInputEl().dom.getAttribute("name");
if (!n.equals("")) {
return n;
}
}
return name;
}
/**
* Returns the original value of the field, which is the value of the field
* when it is first rendered.
*
* @return the original value
*/
public D getOriginalValue() {
return originalValue;
}
/**
* Returns the field's property editor.
*
* @return the property editor
*/
public PropertyEditor<D> getPropertyEditor() {
return propertyEditor;
}
/**
* Returns the raw data value which may or may not be a valid, defined value.
* To return a normalized value see {@link #getValue}.
*
* @return the raw value
*/
public String getRawValue() {
String v = rendered ? getInputEl().getValue() : "";
if (v == null || v.equals(emptyText)) {
return "";
}
return v;
}
/**
* Returns true if the value is validate on blur.
*
* @return the validate on blur state
*/
public boolean getValidateOnBlur() {
return validateOnBlur;
}
/**
* Returns the field's validation delay in milliseconds.
*
* @return the delay in milliseconds
*/
public int getValidationDelay() {
return validationDelay;
}
/**
* Returns the typed value of the field.
*
* @return the fields value
*/
public D getValue() {
if (!rendered) {
return value;
}
String v = getRawValue();
if (emptyText != null && v.equals(emptyText)) {
return null;
}
if (v == null || v.equals("")) {
return null;
}
try {
return propertyEditor.convertStringValue(v);
} catch (Exception e) {
return null;
}
}
/**
* Returns <code>true</code> if this field is dirty. A field is dirty, if the
* current value is different than it's original value. The original value is
* the value of the field when the field is rendered. Disabled and
* pre-rendered fields are never dirty.
*
* @return the dirty state
*/
public boolean isDirty() {
if (disabled || !rendered) {
return false;
}
return !Util.equalWithNull(getValue(), originalValue);
}
/**
* Returns true if a change event is fired when {@link #setValue(Object)} is
* called.
*
* @return true if the change event is fired
*/
public boolean isFireChangeEventOnSetValue() {
return fireChangeEventOnSetValue;
}
/**
* Returns true if the label is hidden.
*
* @return the hide label state
*/
public boolean isHideLabel() {
return hideLabel;
}
/**
* Returns true if the field is inside an editor.
*
* @return true if inside an editor
*/
public boolean isInEditor() {
return inEditor;
}
/**
* Returns the read only state.
*
* @return <code>true</code> if read only, otherwise <code>false</code>
*/
public boolean isReadOnly() {
return readOnly;
}
public boolean isValid() {
return isValid(false);
}
/**
* Returns whether or not the field value is currently valid.
*
* @param preventMark true for silent validation (no invalid event and field
* is not marked invalid)
*
* @return <code>true</code> if the value is valid, otherwise
* <code>false</code>
*/
public boolean isValid(boolean preventMark) {
if (disabled) {
return true;
}
boolean restore = this.preventMark;
this.preventMark = preventMark;
boolean result = validateValue(getRawValue());
if (result) {
activeErrorMessage = null;
}
this.preventMark = restore;
return result;
}
/**
* Marks this field as invalid. Validation will still run if called again, and
* the error message will be changed or cleared based on validation. To set a
* error message that will not be cleared until manually cleared see
* {@link #forceInvalid(String)}
*
* @param msg the validation message
*/
public void markInvalid(String msg) {
msg = Format.htmlEncode(msg == null ? getMessages().getInvalidText() : msg);
activeErrorMessage = msg;
if (!rendered || preventMark) {
return;
}
getInputEl().addStyleName(invalidStyle);
if ("side".equals(messageTarget)) {
if (errorIcon == null) {
errorIcon = new WidgetComponent(getImages().getInvalid().createImage());
Element p = el().getParent().dom;
errorIcon.render(p);
errorIcon.setHideMode(HideMode.VISIBILITY);
errorIcon.hide();
errorIcon.setStyleAttribute("display", "block");
errorIcon.el().makePositionable(true);
errorIcon.getAriaSupport().setRole("alert");
if (GXT.isAriaEnabled()) {
setAriaState("aria-describedby", errorIcon.getId());
errorIcon.setTitle(getErrorMessage());
}
} else if (!errorIcon.el().isConnected()) {
Element p = el().getParent().dom;
p.appendChild(errorIcon.getElement());
}
if (!errorIcon.isAttached()) {
ComponentHelper.doAttach(errorIcon);
}
alignErrorIcon();
if (GXT.isIE || GXT.isOpera) {
alignErrorIcon();
}
// needed to prevent flickering
DeferredCommand.addCommand(new Command() {
public void execute() {
if (errorIcon.isAttached()) {
errorIcon.show();
}
}
});
errorIcon.setToolTip(msg);
errorIcon.getToolTip().addStyleName("x-form-invalid-tip");
el().repaint();
} else if ("title".equals(messageTarget)) {
setTitle(msg);
} else if ("tooltip".equals(messageTarget)) {
setToolTip(msg);
getToolTip().addStyleName("x-form-invalid-tip");
getToolTip().enable();
} else if ("none".equals(messageTarget)) {
// do nothing
} else {
Element elem = XDOM.getElementById(messageTarget);
if (elem != null) {
elem.setInnerHTML(msg);
}
}
if (GXT.isAriaEnabled()) {
setAriaState("aria-invalid", "true");
}
FieldEvent fe = new FieldEvent(this);
fe.setMessage(msg);
fireEvent(Events.Invalid, fe);
}
public void onComponentEvent(ComponentEvent ce) {
super.onComponentEvent(ce);
FieldEvent fe = new FieldEvent(this);
fe.setEvent(ce.getEvent());
switch (ce.getEventTypeInt()) {
case Event.ONFOCUS:
onFocus(ce);
break;
case Event.ONBLUR:
if (inEditor && GXT.isWindows && GXT.isGecko) {
final ComponentEvent e = ce;
DeferredCommand.addCommand(new Command() {
public void execute() {
onBlur(e);
}
});
} else {
onBlur(ce);
}
break;
case Event.ONCLICK:
// in some cases, focus event is not fired when event preview was
// active when the click is fired
if (!hasFocus) {
focus();
}
onClick(ce);
break;
case Event.ONKEYUP:
onKeyUp(fe);
break;
case Event.ONKEYDOWN:
onKeyDown(fe);
if (KeyNav.getKeyEvent().getEventCode() == Event.ONKEYDOWN) {
fireKey(fe);
}
break;
case Event.ONKEYPRESS:
onKeyPress(fe);
if (KeyNav.getKeyEvent().getEventCode() == Event.ONKEYPRESS) {
fireKey(fe);
}
break;
}
}
/**
* Removes a CSS style name from the input element of this field.
*
* @param style the style name
*/
public void removeInputStyleName(String style) {
if (rendered) {
El inputEl = getInputEl();
if (inputEl != null) {
inputEl.removeStyleName(style);
}
} else if (inputStyle != null && style != null) {
String[] s = inputStyle.split(" ");
inputStyle = "";
for (int i = 0; i < s.length; i++) {
if (!s[i].equals(style)) {
inputStyle += " " + s[i];
}
}
}
}
/**
* Removes the key listener.
*
* @param listener the key listener
*/
public void removeKeyListener(KeyListener listener) {
removeListener(Events.KeyPress, listener);
removeListener(Events.KeyUp, listener);
removeListener(Events.KeyDown, listener);
}
/**
* Resets the current field value to the originally loaded value and clears
* any validation messages.
*/
public void reset() {
boolean restore = preventMark;
preventMark = true;
setValue(originalValue);
preventMark = restore;
clearInvalid();
}
/**
* Sets whether the value is validated on each key press (defaults to false).
*
* @param autoValidate true to validate on each key press
*/
public void setAutoValidate(boolean autoValidate) {
if (!this.autoValidate && autoValidate) {
validationTask = new DelayedTask(new Listener<BaseEvent>() {
public void handleEvent(BaseEvent be) {
validate();
}
});
} else if (!autoValidate && validationTask != null) {
validationTask.cancel();
validationTask = null;
}
this.autoValidate = autoValidate;
}
/**
* Sets the default text to display in an empty field.
*
* @param emptyText the empty text
*/
public void setEmptyText(String emptyText) {
this.emptyText = emptyText;
}
/**
* Sets the field's label.
*
* @param fieldLabel the label
*/
public void setFieldLabel(String fieldLabel) {
this.fieldLabel = fieldLabel;
if (rendered) {
El elem = findLabelElement();
if (elem != null) {
elem.setInnerHtml(fieldLabel + labelSeparator);
}
}
}
/**
* True to fire a change event when {@link #setValue(Object)} is called
* (defaults to false).
*
* @param fireChangeEventOnSetValue true to fire a change event
*/
public void setFireChangeEventOnSetValue(boolean fireChangeEventOnSetValue) {
this.fireChangeEventOnSetValue = fireChangeEventOnSetValue;
}
/**
* True to completely hide the label element (defaults to false, pre-render).
*
* @param hideLabel true to hide the label
*/
public void setHideLabel(boolean hideLabel) {
this.hideLabel = hideLabel;
}
public void setImages(FieldImages images) {
this.images = images;
}
/**
* True to mark this field being in an editor.
*
* @param inEditor true mark this field being in an editor
*/
public void setInEditor(boolean inEditor) {
this.inEditor = inEditor;
}
/**
* Sets a style attribute on the input element.
*
* @param attr the attribute
* @param value the attribute value
*/
public void setInputStyleAttribute(String attr, String value) {
if (rendered) {
getInputEl().setStyleAttribute(attr, value);
} else {
inputStyles += attr + ":" + value + ";";
}
}
/**
* The standard separator to display after the text of each form label
* (defaults to the value of {@link FormLayout#setLabelSeparator(String)},
* which is a colon ':' by default).
*
* @param labelSeparator the label separator or "" for none
*/
public void setLabelSeparator(String labelSeparator) {
this.labelSeparator = labelSeparator;
}
/**
* A CSS style specification to apply directly to this field's label. For
* example, <code>labelStyle: 'font-weight:bold;'</code>
*
* @param labelStyle the label style
*/
public void setLabelStyle(String labelStyle) {
assertPreRender();
this.labelStyle = labelStyle;
}
/**
* Sets the field's messages.
*
* @param messages the messages
*/
public void setMessages(FieldMessages messages) {
this.messages = messages;
}
/**
* The location where error text should display. Should be one of the
* following values (defaults to 'side'): <code><pre>
* Value Description
* ----------- ----------------------------------------------------------------------
* tooltip Display a tool tip when the user hovers over the field
* title Display a default browser title attribute popup
* side Add an error icon to the right of the field with a popup on hover
* none Do not display an error message
* [element id] Add the error text directly to the innerHTML of the specified element
* </pre></code>
*
* @param messageTarget the message target
*/
public void setMessageTarget(String messageTarget) {
this.messageTarget = messageTarget;
}
/**
* Sets the field's HTML name attribute.
*
* @param name the name
*/
public void setName(String name) {
this.name = name;
if (rendered) {
// we need to remove the old one first, else ie6 goes crazy.
getInputEl().dom.removeAttribute("name");
if (name != null) {
((InputElement) getInputEl().dom.cast()).setName(name);
}
}
}
/**
* Updates the original value of the field. The originalValue is the value of
* the field when it is rendered. This method is useful when a form / field is
* being reused and the originaValue needs to be reset.
*
* @param originalValue the original value
*/
public void setOriginalValue(D originalValue) {
this.originalValue = originalValue;
}
/**
* Sets the field's property editor which is used to translate typed values to
* string, and string values back to typed values.
*
* @param propertyEditor the property editor
*/
public void setPropertyEditor(PropertyEditor<D> propertyEditor) {
this.propertyEditor = propertyEditor;
}
/**
* Sets the underlying DOM field's value directly, bypassing validation. To
* set the value with validation see {@link #setValue}.
*
* @param value the raw value
*/
public void setRawValue(String value) {
if (rendered) {
getInputEl().setValue(value == null ? "" : value);
}
}
/**
* Sets the field's read only state.
*
* @param readOnly the read only state
*/
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
if (rendered) {
el().setStyleName(readOnlyFieldStyle, readOnly);
getInputEl().dom.setPropertyBoolean("readOnly", readOnly);
}
}
/**
* Sets the tab index.
*
* @param index the tab index value
*/
public void setTabIndex(int index) {
this.tabIndex = index;
if (rendered) {
getInputEl().dom.setPropertyInt("tabIndex", index);
}
}
/**
* Sets whether the field should validate when it loses focus (defaults to
* true).
*
* @param validateOnBlur true to validate on blur, otherwise false
*/
public void setValidateOnBlur(boolean validateOnBlur) {
this.validateOnBlur = validateOnBlur;
}
/**
* Sets length of time in milliseconds after user input begins until
* validation is initiated (defaults to 250).
*
* @param validationDelay the delay in milliseconds
*/
public void setValidationDelay(int validationDelay) {
this.validationDelay = validationDelay;
}
/**
* Sets a data value into the field and validates it. If the field is
* rendered, To set the value directly without validation see
* {@link #setRawValue}.
*
* @param value the value to set
*/
public void setValue(D value) {
D oldValue = this.value;
this.value = value;
if (rendered) {
String v = value == null ? "" : propertyEditor.getStringValue(value);
setRawValue(v);
validate(preventMark);
}
if (fireChangeEventOnSetValue) {
fireChangeEvent(oldValue, value);
}
}
/**
* Updates the original value of the field. This method is useful when a form
* / field is being reused and the originaValue needs to be reset.
*
* @param value the new original value
*/
public void updateOriginalValue(D value) {
originalValue = value;
}
/**
* Validates the field value.
*
* @return <code>true</code> if valid, otherwise <code>false</code>
*/
public boolean validate() {
return validate(false);
}
/**
* Validates the field value.
*
* @param preventMark true to not mark the field valid and fire invalid event
* when invalid
* @return <code>true</code> if valid, otherwise <code>false</code>
*/
public boolean validate(boolean preventMark) {
if (disabled) {
clearInvalid();
return true;
}
boolean restore = this.preventMark;
this.preventMark = preventMark;
boolean result = validateValue(getRawValue());
this.preventMark = restore;
if (result) {
clearInvalid();
activeErrorMessage = null;
}
return result;
}
@Override
protected void afterRender() {
super.afterRender();
initValue();
}
protected void alignErrorIcon() {
DeferredCommand.addCommand(new Command() {
public void execute() {
errorIcon.el().alignTo(getElement(), "tl-tr", new int[] {2, 3});
}
});
}
@Override
protected ComponentEvent createComponentEvent(Event event) {
return new FieldEvent(this);
}
@Override
protected void doDetachChildren() {
super.doDetachChildren();
if (errorIcon != null && errorIcon.isAttached()) {
errorIcon.setVisible(false);
ComponentHelper.doDetach(errorIcon);
}
}
protected El findLabelElement() {
if (rendered) {
El elem = el().findParent(".x-form-item", 5);
if (elem != null) {
return elem.firstChild();
}
}
return null;
}
protected void fireChangeEvent(Object oldValue, Object value) {
if (!Util.equalWithNull(oldValue, value)) {
FieldEvent e = new FieldEvent(this);
e.setOldValue(oldValue);
e.setValue(value);
fireEvent(Events.Change, e);
}
}
protected void fireKey(FieldEvent fe) {
if (fe.isSpecialKey()) {
fireEvent(Events.SpecialKey, fe);
}
}
/**
* Provides support for wrapping the actual input element.
*
* @return the input element
*/
protected El getInputEl() {
return el();
}
protected El getStyleEl() {
return el();
}
protected void initValue() {
if (value != null) {
setValue(value);
}
}
protected void onBlur(ComponentEvent be) {
if (hasFocus) {
if (getInputEl() != null) {
getInputEl().removeStyleName(focusStyle);
}
hasFocus = false;
if (validateOnBlur) {
validate();
}
D v = getValue();
value = v;
fireChangeEvent(focusValue, v);
fireEvent(Events.Blur, new FieldEvent(this));
}
}
protected void onClick(ComponentEvent ce) {
}
@Override
protected void onDetach() {
if (validationTask != null) {
validationTask.cancel();
}
super.onDetach();
}
@Override
protected void onDisable() {
super.onDisable();
getInputEl().disable();
}
@Override
protected void onEnable() {
super.onEnable();
getInputEl().enable();
}
protected void onFocus(ComponentEvent ce) {
if (!hasFocus) {
if (getInputEl() != null) {
getInputEl().addStyleName(focusStyle);
}
hasFocus = true;
focusValue = getValue();
fireEvent(Events.Focus, new FieldEvent(this));
}
}
@Override
protected void onHide() {
super.onHide();
if (errorIcon != null && errorIcon.isAttached()) {
errorIcon.hide();
}
}
protected void onKeyDown(FieldEvent fe) {
fireEvent(Events.KeyDown, new FieldEvent(this, fe.getEvent()));
}
protected void onKeyPress(FieldEvent fe) {
fireEvent(Events.KeyPress, new FieldEvent(this, fe.getEvent()));
}
protected void onKeyUp(FieldEvent fe) {
if (autoValidate && validationTask != null) {
validationTask.delay(validationDelay);
}
fireEvent(Events.KeyUp, new FieldEvent(this, fe.getEvent()));
}
@Override
protected void onRender(Element parent, int index) {
super.onRender(parent, index);
addStyleName(fieldStyle);
String type = getInputEl().dom.getAttribute("type");
if (type.equals("password")) {
type = "text";
}
if (!type.equals("")) {
getInputEl().addStyleName("x-form-" + type);
}
setName(name);
if (readOnly) {
setReadOnly(true);
}
setTabIndex(tabIndex);
if (inputStyle != null) {
addInputStyleName(inputStyle);
inputStyle = null;
}
if (inputStyles != null && !inputStyles.equals("")) {
getInputEl().applyStyles(inputStyles);
inputStyles = null;
}
originalValue = value;
getInputEl().addEventsSunk(Event.FOCUSEVENTS);
sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.FOCUSEVENTS | Event.KEYEVENTS);
}
@Override
protected void onResize(int width, int height) {
super.onResize(width, height);
if (errorIcon != null && errorIcon.isAttached()) {
alignErrorIcon();
}
}
@Override
protected void onShow() {
super.onShow();
if (errorIcon != null && errorIcon.isAttached()) {
errorIcon.show();
}
}
/**
* Subclasses should provide the validation implementation by overriding this.
*
* @param value the value to validate
*
* @return <code>true</code> for valid
*/
protected boolean validateValue(String value) {
if (forceInvalidText != null) {
markInvalid(forceInvalidText);
return false;
}
return true;
}
}