package org.vaadin.viritin.fields; import org.vaadin.viritin.fluency.ui.FluentCustomField; import org.vaadin.viritin.util.HtmlElementPropertySetter; import com.vaadin.event.FieldEvents; import com.vaadin.event.FieldEvents.BlurListener; import com.vaadin.event.FieldEvents.FocusListener; import com.vaadin.shared.Registration; import com.vaadin.ui.Component; import com.vaadin.ui.CustomField; import com.vaadin.ui.TextField; /** * @param <T> field value type * @author Matti Tahvonen */ public abstract class AbstractNumberField<S extends AbstractNumberField<S, T>, T> extends CustomField<T> implements FieldEvents.FocusNotifier, FieldEvents.BlurNotifier, FluentCustomField<S, T> { private static final long serialVersionUID = 5925606478174987241L; private String htmlFieldType = "number"; protected T value; protected TextField tf = new TextField() { private static final long serialVersionUID = 6823601969399906594L; @Override public void beforeClientResponse(boolean initial) { super.beforeClientResponse(initial); configureHtmlElement(); } }; protected void configureHtmlElement() { s.setProperty("type", getHtmlFieldType()); // prevent all but numbers with a simple js s.setJavaScriptEventHandler("keypress", "function(e) {var c = viritin.getChar(e); return c==null || /^[-\\d\\n\\t\\r]+$/.test(c);}"); } private boolean ignoreValueChange = false; protected HtmlElementPropertySetter s = new HtmlElementPropertySetter(tf); protected ValueChangeListener<String> vcl = new ValueChangeListener<String>() { private static final long serialVersionUID = 5034199201545161061L; @Override public void valueChange(ValueChangeEvent<String> event) { if (!ignoreValueChange) { T old = getValue(); String value = event.getValue(); if (value != null) { userInputToValue(value); fireEvent(new ValueChangeEvent(AbstractNumberField.this, old, true)); } else { setValue(null); } } } }; public AbstractNumberField() { tf.addValueChangeListener(vcl); } protected abstract void userInputToValue(String str); @Override protected Component initContent() { return tf; } @Override protected void doSetValue(T value) { this.value = value; ignoreValueChange = true; if (value == null) { tf.clear(); } else { tf.setValue(valueToPresentation(value)); } ignoreValueChange = false; } protected String valueToPresentation(T newValue) { return newValue.toString(); } public String getHtmlFieldType() { return htmlFieldType; } /** * Sets the type property of the input field used on the browser. "number" * by default. * * @param htmlFieldType the type value */ public void setHtmlFieldType(String htmlFieldType) { this.htmlFieldType = htmlFieldType; } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); tf.setEnabled(enabled); } @Override public void setReadOnly(boolean readOnly) { super.setReadOnly(readOnly); tf.setReadOnly(readOnly); } @Override public void setWidth(float width, Unit unit) { super.setWidth(width, unit); if (tf != null) { if (width != -1) { tf.setWidth("100%"); } else { tf.setWidth(null); } } } @Override public Registration addBlurListener(BlurListener listener) { return tf.addBlurListener(listener); } @Override public Registration addFocusListener(FocusListener listener) { return tf.addFocusListener(listener); } /** * Adds a BlurListener to the Component which gets fired when a Field loses * keyboard focus, returning this instance in a fluent fashion. * * @param listener the listener to be added * @return this instance */ public AbstractNumberField<S, T> withBlurListener(BlurListener listener) { addBlurListener(listener); return this; } /** * Adds a FocusListener to the Component which gets fired when a Field * receives keyboard focus, returning this instance in a fluent fashion. * * @param listener the listener to be added * @return this instance */ public AbstractNumberField<S, T> withFocusListener(FocusListener listener) { addFocusListener(listener); return this; } public S withPlaceHolder(String placeHolderText) { tf.setPlaceholder(placeHolderText); return (S) this; } }