1. #1
    Ext User fother's Avatar
    Join Date
    Sep 2007
    Location
    Brazil
    Posts
    744
    Vote Rating
    -1
    fother is an unknown quantity at this point

      0  

    Talking input mask plugin

    input mask plugin


    now its possible add mask in TextField type of String

    how add mask in for your fields
    create one class called TextFieldMask and put into the client package in your project paste the source code.. for more details see the example..

    Example
    Code:
    	public void onModuleLoad() {
    
    		FormPanel form = new FormPanel();
    		form.setLabelWidth(250);
    
    		TextFieldMask field = new TextFieldMask("99/99/9999");
    		field.setFieldLabel("99/99/9999");
    		form.add(field);
    
    		field = new TextFieldMask("(999) 999-9999");
    		field.setFieldLabel("(999) 999-9999");
    		form.add(field);
    
    		field = new TextFieldMask("(999) 999-9999& x99999");
    		field.setFieldLabel("(999) 999-9999& x99999");
    		form.add(field);
    
    		field = new TextFieldMask("99-9999999");
    		field.setFieldLabel("99-9999999");
    		form.add(field);
    
    		field = new TextFieldMask("999-99-9999");
    		field.setFieldLabel("999-99-9999");
    		form.add(field);
    
    		field = new TextFieldMask("a*-999-a999");
    		field.setFieldLabel("a*-999-a999");
    		form.add(field);
    
    		RootPanel.get().add(form);
    
    	}
    Source Code
    Code:
    import java.util.HashMap;
    import java.util.Map;
    
    import com.extjs.gxt.ui.client.event.ComponentEvent;
    import com.extjs.gxt.ui.client.event.FieldEvent;
    import com.extjs.gxt.ui.client.widget.form.TextField;
    import com.google.gwt.user.client.Element;
    import com.google.gwt.user.client.ui.KeyboardListener;
    
    public class TextFieldMask extends TextField<String> {
    
    	public class Settings {
    
    		private String placeHolder;
    
    		public Settings() {
    
    		}
    
    		public Settings(String placeHolder) {
    			this.placeHolder = placeHolder;
    		}
    
    		public String getPlaceHolder() {
    			return placeHolder;
    		}
    
    		public void setPlaceHolder(String placeHolder) {
    			this.placeHolder = placeHolder;
    		}
    
    	}
    
    	private final String mask;
    
    	private int len;
    
    	private Settings settings;
    	private int partialPosition;
    	private String[] buffer;
    	private boolean ignore;
    	private String focusText;
    	private String[] tests;
    
    	private Integer firstNonMaskPos;
    	private int cursorBegin = -1;
    
    	private int cursorEnd = -1;
    
    	private static final Map<String, String> defs;
    
    	static {
    
    		defs = new HashMap<String, String>();
    		defs.put("9", "[0-9]");
    		defs.put("a", "[A-Za-z]");
    		defs.put("*", "[A-Za-z0-9]");
    
    	}
    
    	private static boolean cotainDef(String key) {
    
    		if (defs.get(key) != null) {
    			return true;
    		} else {
    			return false;
    		}
    	}
    
    	private static String getDef(String key) {
    		return defs.get(key);
    	}
    
    	public TextFieldMask(String mask) {
    		this.mask = mask;
    	}
    
    	private void buffer() {
    
    		String[] aux = split(mask);
    
    		buffer = new String[aux.length];
    
    		for (int i = 0; i < aux.length; i++) {
    
    			if (cotainDef(aux[i])) {
    				buffer[i] = settings.getPlaceHolder();
    			} else {
    				buffer[i] = aux[i];
    			}
    
    		}
    
    	}
    
    	private int checkVal(boolean allow) {
    
    		String test = "";
    
    		if (getValue() != null) {
    			test = getValue();
    		}
    
    		int lastMatch = -1;
    
    		int a = 0;
    
    		for (int i = 0, pos = 0; i < len; i++) {
    
    			if (tests[i] != null) {
    
    				buffer[i] = settings.getPlaceHolder();
    
    				while (pos++ < test.length()) {
    
    					String c = String.valueOf(test.charAt(pos - 1));
    
    					if (c.matches(tests[i])) {
    
    						buffer[i] = String.valueOf(c);
    						lastMatch = i;
    						break;
    					}
    				}
    				if (pos > test.length()) {
    					break;
    				}
    			} else if (i != partialPosition) {
    
    				try {
    
    					char d = test.charAt(pos);
    
    					if (buffer[i].equals(String.valueOf(d))) {
    
    						pos++;
    						lastMatch = i;
    					}
    
    				} catch (Exception e) {
    					continue;
    				}
    			}
    
    			a = i;
    		}
    
    		if (!allow && lastMatch + 1 < partialPosition) {
    
    			setValue("");
    			clearBuffer(0, len);
    
    		} else if (allow || lastMatch + 1 >= partialPosition) {
    
    			writeBuffer();
    
    			if (!allow) {
    
    				if (getValue() != null) {
    					setValue(getValue().substring(0, lastMatch + 1));
    				}
    			}
    		}
    
    		return a;
    
    	}
    
    	private void clearBuffer(int start, int end) {
    
    		for (int i = start; i < end && i < len; i++) {
    			if (tests[i] != null) {
    				buffer[i] = settings.getPlaceHolder();
    			}
    		}
    
    	}
    
    	private void each() {
    
    		for (int i = 0; i < tests.length; i++) {
    
    			String c = tests[i];
    
    			if (c == "?") {
    
    				len--;
    				partialPosition = i;
    
    			} else if (cotainDef(c)) {
    
    				tests[i] = getDef(c);
    
    				if (firstNonMaskPos == null) {
    					firstNonMaskPos = tests.length - 1;
    				}
    
    			} else {
    				tests[i] = null;
    			}
    
    		}
    
    	}
    
    	private void maskField() {
    
    		settings = new Settings("_");
    
    		tests = new String[] {};
    		partialPosition = mask.length();
    		firstNonMaskPos = null;
    		len = mask.length();
    
    		tests = split(mask);
    
    		each();
    		buffer();
    
    		ignore = false;
    
    		focusText = "";
    
    		if (getValue() != null) {
    			focusText = getValue();
    		}
    
    		if (!isReadOnly()) {
    
    			checkVal(false);
    		}
    
    	}
    
    	@Override
    	protected void onBlur(ComponentEvent be) {
    
    		super.onBlur(be);
    
    		checkVal(false);
    	}
    
    	@Override
    	protected void onFocus(ComponentEvent be) {
    
    		super.onFocus(be);
    
    		focusText = "";
    
    		if (getValue() != null) {
    			focusText = getValue();
    		}
    
    		int pos = checkVal(false);
    		writeBuffer();
    
    		if (pos == mask.length()) {
    			cursorBegin = 0;
    			cursorEnd = pos;
    
    			select(0, pos);
    		} else {
    
    			cursorBegin = pos;
    			cursorEnd = pos;
    
    			setCursorPos(pos);
    		}
    	}
    
    	@Override
    	protected void onKeyDown(FieldEvent fe) {
    
    		super.onKeyDown(fe);
    
    		int k = fe.getKeyCode();
    
    		ignore = k < 16 || k > 16 && k < 32 || k > 32 && k < 41;
    
    		// delete selection before proceeding
    		if (cursorBegin - cursorEnd != 0 && (!ignore || k == KeyboardListener.KEY_BACKSPACE || k == KeyboardListener.KEY_DELETE)) {
    			clearBuffer(cursorBegin, cursorEnd);
    		}
    
    		// backspace, delete, and escape get special treatment
    		if (k == KeyboardListener.KEY_BACKSPACE || k == KeyboardListener.KEY_DELETE) {
    
    			shiftL(getCursorPos() + (k == KeyboardListener.KEY_DELETE ? 0 : -1));
    			fe.stopEvent();
    		} else if (k == KeyboardListener.KEY_ESCAPE) {// escape
    			setValue(focusText);
    			fe.stopEvent();
    		}
    	}
    
    	@Override
    	protected void onKeyPress(FieldEvent fe) {
    
    		super.onKeyPress(fe);
    
    		int k = fe.getKeyCode();
    
    		if (ignore) {
    			// Fixes Mac FF bug on backspace
    
    			if (k == KeyboardListener.KEY_BACKSPACE) {
    				fe.stopEvent();
    			}
    
    			return;
    		}
    
    		if (fe.isControlKey() || fe.isAltKey()) {// Ignore
    
    			fe.stopEvent();
    
    		} else if (k >= 32 && k <= 125 || k > 186) {// typeable characters
    
    			int p = seekNext(getCursorPos() - 1);
    
    			if (p < len) {
    
    				String c = String.valueOf((char) fe.getKeyCode());
    
    				if (c.matches(tests[p])) {
    
    					shiftR(p);
    					buffer[p] = c;
    					writeBuffer();
    					int next = seekNext(p);
    
    					setCursorPos(next);
    
    					cursorBegin = next;
    					cursorEnd = next;
    				}
    			}
    		}
    
    		fe.stopEvent();
    	}
    
    	@Override
    	protected void onRender(Element target, int index) {
    
    		super.onRender(target, index);
    
    		maskField();
    	}
    
    	private int seekNext(int index) {
    
    		while (++index <= len) {
    
    			try {
    				if (tests[index] != null) {
    					break;
    				}
    			} catch (Exception e) {
    				break;
    			}
    		}
    
    		return index;
    
    	}
    
    	private void shiftL(int index) {
    
    		for (int i = index; i >= 0; i--) {
    
    			if (tests[i] != null) {
    
    				index = i;
    				break;
    			}
    		}
    
    		for (int i = index; i < len; i++) {
    
    			if (tests[i] != null) {
    
    				buffer[i] = settings.getPlaceHolder();
    
    				int j = seekNext(i);
    
    				if (j < len && buffer[j].matches(tests[i])) {
    					buffer[i] = buffer[j];
    				} else {
    					break;
    				}
    			}
    		}
    
    		writeBuffer();
    
    		setCursorPos(index);
    
    	}
    
    	private void shiftR(int index) {
    
    		String c = settings.getPlaceHolder();
    
    		for (int i = index; i < len; i++) {
    
    			if (tests[i] != null) {
    
    				int j = seekNext(i);
    				String t = buffer[i];
    				buffer[i] = c;
    				if (j < len && t.matches(tests[j])) {
    					c = t;
    				} else {
    					break;
    				}
    			}
    		}
    
    	}
    
    	private String[] split(String text) {
    
    		int length = text.length();
    
    		String[] array = new String[length];
    
    		for (int i = 0; i < length; i++) {
    			array[i] = String.valueOf(text.charAt(i));
    		}
    
    		return array;
    	}
    
    	private void writeBuffer() {
    
    		String valueAux = "";
    
    		for (String element2 : buffer) {
    
    			valueAux += element2;
    		}
    
    		setValue(valueAux);
    
    	}
    
    }
    TO DO LIST
    • Paste into field - broken
    • create the config - to show or not the replace holder and change it
    • turn on create your regex expression - for example pass "H" and your regex, when you create the mask and set "H" validate the regex passed for parameter
    • allow pass various mask
    Attached Images

  2. #2
    Ext User
    Join Date
    Mar 2009
    Posts
    7
    Vote Rating
    0
    cstdenis is on a distinguished road

      0  

    Default


    This is very useful.

    Some suggestions for improvement:
    * Only return the value that is entered, not the underscores.
    * Add support for optional characters. In your example you have "(999) 999-9999& x99999" but that is a problem for any phone number that does not have an ext since you can't leave it blank (can't put in a country code either).
    * This would make a nice addition to the DateField

  3. #3
    Ext User fother's Avatar
    Join Date
    Sep 2007
    Location
    Brazil
    Posts
    744
    Vote Rating
    -1
    fother is an unknown quantity at this point

      0  

    Default


    Quote Originally Posted by cstdenis View Post
    * Only return the value that is entered, not the underscores.
    of course.. I can create the config.. to show underscore or not.. and set other character that can be different the underscore

    Quote Originally Posted by cstdenis View Post
    * Add support for optional characters. In your example you have "(999) 999-9999& x99999" but that is a problem for any phone number that does not have an ext since you can't leave it blank (can't put in a country code either).
    sorry... I dont understand

    Quote Originally Posted by cstdenis View Post
    * This would make a nice addition to the DateField
    the problem to do this.. is that DateField extends Field.. and I needed create all Fields again (MyTextFieldMask, MyDateFieldMask and extends to MyField - isnt difficult.. but for this time.. I need first test if what I do its ok.. after I can implements this) good idea too..


    thanks to reply.. other problem occurs when you paste anything.. I could not find a solution yet

  4. #4
    Ext User
    Join Date
    Mar 2009
    Posts
    7
    Vote Rating
    0
    cstdenis is on a distinguished road

      0  

    Default


    Quote Originally Posted by fother View Post
    sorry... I dont understand

    If the phone number mask is "(999) 999-9999 x999" but the phone number you need to enter is 555-555-1234 then what? That mask will not accept (555) 555-1234 because it's missing characters.

    But if I were to use a mask of "(999) 999-9999", then there is no way to input something like (555) 555-4321 x123. A phone number field generally needs to accept a few variations of numbers.

    Perhaps this could be best solved by accepting an array of Strings in the constructor and require that any 1 input mask match.

  5. #5
    Ext User fother's Avatar
    Join Date
    Sep 2007
    Location
    Brazil
    Posts
    744
    Vote Rating
    -1
    fother is an unknown quantity at this point

      0  

    Default


    9 = [0-9]
    A = [A-Za-z]
    * = [A-Za-z0-9]
    • if you create one mask using "9" can be replaced by (0,1,2,3,4,5,6,7,8,9) - only numbers
    • if you create one mask using "A" can be replaced by (A,b,c...X,Y,z) - uppercase and lowercase letters
    • if you create one mask using "*" cab be replaced by (0,1,g,E,u,P) - can be replaced by numbers and letters

    you are suggesting create one mask, for example "h" that can be replaced by your regex?

  6. #6
    Ext User fother's Avatar
    Join Date
    Sep 2007
    Location
    Brazil
    Posts
    744
    Vote Rating
    -1
    fother is an unknown quantity at this point

      0  

    Default


    completing my reply..

    if you dont set [9,A,*] the mask assume that you need this character in this position..

    example: (XJUA) 9987456
    can return: (XJUK) 1187456
    can return: (XJUC) 2487456

    only when have A and 9 you can replace by the regex

  7. #7
    Ext User
    Join Date
    Mar 2009
    Posts
    7
    Vote Rating
    0
    cstdenis is on a distinguished road

      0  

    Default


    I'm thinking more like modifiers.

    9+ = /[0-9]+/
    9* = /[0-9]*/
    9? = /[0-9]?/
    a+ = /[A-Za-z]+/
    a* = /[A-Za-z]*/
    a? = /[A-Za-z]?/
    h = /[A-Za-z0-9]/
    h+ = /[A-Za-z0-9]+/
    h* = /[A-Za-z0-9]*/
    h? = /[A-Za-z0-9]?/

    Or maybe just accept arbitrary regex as the mask.

    What I want is a mask for phone number along the lines of

    /([0-9]+ )?+\([0-9]{3}\)\ [0-9]{3}\-[0-9]{4}( x[0-9]+)?/

    Basically (555) 555-1234 with optional country code (followed by space) and optional extension at the end (prefixed by a space and the character x).


    The other way I see of making this kind of thing work is

    field = new TextFieldMask({"(999) 999-9999", "9 (999) 999-9999", "(999) 999-9999 x9999"});

  8. #8
    Ext User fother's Avatar
    Join Date
    Sep 2007
    Location
    Brazil
    Posts
    744
    Vote Rating
    -1
    fother is an unknown quantity at this point

      0  

    Default


    hmm.. you suggest that I can use different mask for one field?

  9. #9
    Ext User
    Join Date
    Mar 2009
    Posts
    7
    Vote Rating
    0
    cstdenis is on a distinguished road

      0  

    Default


    Yes.

    I don't know how hard it would be to make it work, but it should be possible in theory.

  10. #10
    Ext User fother's Avatar
    Join Date
    Sep 2007
    Location
    Brazil
    Posts
    744
    Vote Rating
    -1
    fother is an unknown quantity at this point

      0  

    Default


    hmm... I can try