1. #1
    Ext User bobbicat71's Avatar
    Join Date
    Dec 2007
    Location
    Italy
    Posts
    20
    Vote Rating
    1
    bobbicat71 is on a distinguished road

      1  

    Default InputTextMask plugin for Textfield

    InputTextMask plugin for Textfield


    Hi all,
    here is a plugin for textfield that adds a mask input to the field.

    This is the latest version:
    Code:
    // $Id: InputTextMask.js 293638 2008-02-04 14:33:36Z UE014015 $
    
    Ext.namespace('Ext.ux.netbox');
    
    /**
     * InputTextMask script used for mask/regexp operations.
     * Mask Individual Character Usage:
     * 9 - designates only numeric values
     * L - designates only uppercase letter values
     * l - designates only lowercase letter values
     * A - designates only alphanumeric values
     * X - denotes that a custom client script regular expression is specified</li>
     * All other characters are assumed to be "special" characters used to mask the input component.
     * Example 1:
     * (999)999-9999 only numeric values can be entered where the the character
     * position value is 9. Parenthesis and dash are non-editable/mask characters.
     * Example 2:
     * 99L-ll-X[^A-C]X only numeric values for the first two characters,
     * uppercase values for the third character, lowercase letters for the
     * fifth/sixth characters, and the last character X[^A-C]X together counts
     * as the eighth character regular expression that would allow all characters
     * but "A", "B", and "C". Dashes outside the regular expression are non-editable/mask characters.
     * @constructor
     * @param (String) mask The InputTextMask
     * @param (boolean) clearWhenInvalid True to clear the mask when the field blurs and the text is invalid. Optional, default is true.
     */
    Ext.ux.netbox.InputTextMask = function(mask,clearWhenInvalid) {
    
        if(clearWhenInvalid === undefined)
    		this.clearWhenInvalid = true;
    	else
    		this.clearWhenInvalid = clearWhenInvalid;
        this.rawMask = mask;
        this.viewMask = '';
        this.maskArray = new Array();
        var mai = 0;
        var regexp = '';
        for(var i=0; i<mask.length; i++){
            if(regexp){
                if(regexp == 'X'){
                    regexp = '';
                }
                if(mask.charAt(i) == 'X'){
                    this.maskArray[mai] = regexp;
                    mai++;
                    regexp = '';
                } else {
                    regexp += mask.charAt(i);
                }
            } else if(mask.charAt(i) == 'X'){
                regexp += 'X';
                this.viewMask += '_';
            } else if(mask.charAt(i) == '9' || mask.charAt(i) == 'L' || mask.charAt(i) == 'l' || mask.charAt(i) == 'A') {
                this.viewMask += '_';
                this.maskArray[mai] = mask.charAt(i);
                mai++;
            } else {
                this.viewMask += mask.charAt(i);
                this.maskArray[mai] = RegExp.escape(mask.charAt(i));
                mai++;
            }
        }
    
        this.specialChars = this.viewMask.replace(/(L|l|9|A|_|X)/g,'');
    };
    
    Ext.ux.netbox.InputTextMask.prototype = {
    
        init : function(field) {
            this.field = field;
    
            if (field.rendered){
                this.assignEl();
            } else {
                field.on('render', this.assignEl, this);
            }
    
            field.on('blur',this.removeValueWhenInvalid, this);
            field.on('focus',this.processMaskFocus, this);
        },
    
        assignEl : function() {
            this.inputTextElement = this.field.getEl().dom;
            this.field.getEl().on('keypress', this.processKeyPress, this);
            this.field.getEl().on('keydown', this.processKeyDown, this);
            if(Ext.isSafari || Ext.isIE){
                this.field.getEl().on('paste',this.startTask,this);
                this.field.getEl().on('cut',this.startTask,this);
            }
            if(Ext.isGecko || Ext.isOpera){
                this.field.getEl().on('mousedown',this.setPreviousValue,this);
            }
            if(Ext.isGecko){
              this.field.getEl().on('input',this.onInput,this);
            }
            if(Ext.isOpera){
              this.field.getEl().on('input',this.onInputOpera,this);
            }
        },
        onInput : function(){
            this.startTask(false);
        },
        onInputOpera : function(){
          if(!this.prevValueOpera){
            this.startTask(false);
          }else{
            this.manageBackspaceAndDeleteOpera();
          }
        },
        
        manageBackspaceAndDeleteOpera: function(){
          this.inputTextElement.value=this.prevValueOpera.cursorPos.previousValue;
          this.manageTheText(this.prevValueOpera.keycode,this.prevValueOpera.cursorPos);
          this.prevValueOpera=null;
        },
    
        setPreviousValue : function(event){
            this.oldCursorPos=this.getCursorPosition();
        },
    
        getValidatedKey : function(keycode, cursorPosition) {
            var maskKey = this.maskArray[cursorPosition.start];
            if(maskKey == '9'){
                return keycode.pressedKey.match(/[0-9]/);
            } else if(maskKey == 'L'){
                return (keycode.pressedKey.match(/[A-Za-z]/))? keycode.pressedKey.toUpperCase(): null;
            } else if(maskKey == 'l'){
                return (keycode.pressedKey.match(/[A-Za-z]/))? keycode.pressedKey.toLowerCase(): null;
            } else if(maskKey == 'A'){
                return keycode.pressedKey.match(/[A-Za-z0-9]/);
            } else if(maskKey){
                return (keycode.pressedKey.match(new RegExp(maskKey)));
            }
            return(null);
        },
    
        removeValueWhenInvalid : function() {
            if(this.clearWhenInvalid && this.inputTextElement.value.indexOf('_') > -1){
                this.inputTextElement.value = '';
            }
        },
    
        managePaste : function() {
            if(this.oldCursorPos==null){
              return;
            }
            var valuePasted=this.inputTextElement.value.substring(this.oldCursorPos.start,this.inputTextElement.value.length-(this.oldCursorPos.previousValue.length-this.oldCursorPos.end));
            if(this.oldCursorPos.start<this.oldCursorPos.end){//there is selection...
              this.oldCursorPos.previousValue=
                this.oldCursorPos.previousValue.substring(0,this.oldCursorPos.start)+
                this.viewMask.substring(this.oldCursorPos.start,this.oldCursorPos.end)+
                this.oldCursorPos.previousValue.substring(this.oldCursorPos.end,this.oldCursorPos.previousValue.length);
              valuePasted=valuePasted.substr(0,this.oldCursorPos.end-this.oldCursorPos.start);
            }
            this.inputTextElement.value=this.oldCursorPos.previousValue;
            keycode={unicode :'',
            isShiftPressed: false,
            isTab: false,
            isBackspace: false,
            isLeftOrRightArrow: false,
            isDelete: false,
            pressedKey : ''
            }
            var charOk=false;
            for(var i=0;i<valuePasted.length;i++){
                keycode.pressedKey=valuePasted.substr(i,1);
                keycode.unicode=valuePasted.charCodeAt(i);
                this.oldCursorPos=this.skipMaskCharacters(keycode,this.oldCursorPos);
                if(this.oldCursorPos===false){
                    break;
                }
                if(this.injectValue(keycode,this.oldCursorPos)){
                    charOk=true;
                    this.moveCursorToPosition(keycode, this.oldCursorPos);
                    this.oldCursorPos.previousValue=this.inputTextElement.value;
                    this.oldCursorPos.start=this.oldCursorPos.start+1;
                }
            }
            if(!charOk && this.oldCursorPos!==false){
                this.moveCursorToPosition(null, this.oldCursorPos);
            }
            this.oldCursorPos=null;
        },
    
        processKeyDown : function(e){
            this.processMaskFormatting(e,'keydown');
        },
    
        processKeyPress : function(e){
            this.processMaskFormatting(e,'keypress');
        },
    
        startTask : function(setOldCursor){
            if(this.task==undefined){
                this.task=new Ext.util.DelayedTask(this.managePaste,this);
          }
            if(setOldCursor!== false){
                this.oldCursorPos=this.getCursorPosition();
          }
          this.task.delay(0);
        },
    
        skipMaskCharacters : function(keycode, cursorPos){
            if(cursorPos.start!=cursorPos.end && (keycode.isDelete || keycode.isBackspace))
                return(cursorPos);
            while(this.specialChars.match(RegExp.escape(this.viewMask.charAt(((keycode.isBackspace)? cursorPos.start-1: cursorPos.start))))){
                if(keycode.isBackspace) {
                    cursorPos.dec();
                } else {
                    cursorPos.inc();
                }
                if(cursorPos.start >= cursorPos.previousValue.length || cursorPos.start < 0){
                    return false;
                }
            }
            return(cursorPos);
        },
    
        isManagedByKeyDown : function(keycode){
            if(keycode.isDelete || keycode.isBackspace){
                return(true);
            }
            return(false);
        },
    
        processMaskFormatting : function(e, type) {
            this.oldCursorPos=null;
            var cursorPos = this.getCursorPosition();
            var keycode = this.getKeyCode(e, type);
            if(keycode.unicode==0){//?? sometimes on Safari
                return;
            }
            if((keycode.unicode==67 || keycode.unicode==99) && e.ctrlKey){//Ctrl+c, let's the browser manage it!
                return;
            }
            if((keycode.unicode==88 || keycode.unicode==120) && e.ctrlKey){//Ctrl+x, manage paste
                this.startTask();
                return;
            }
            if((keycode.unicode==86 || keycode.unicode==118) && e.ctrlKey){//Ctrl+v, manage paste....
                this.startTask();
                return;
            }
            if((keycode.isBackspace || keycode.isDelete) && Ext.isOpera){
              this.prevValueOpera={cursorPos: cursorPos, keycode: keycode};
              return;
            }
            if(type=='keydown' && !this.isManagedByKeyDown(keycode)){
                return true;
            }
            if(type=='keypress' && this.isManagedByKeyDown(keycode)){
                return true;
            }
            if(this.handleEventBubble(e, keycode, type)){
                return true;
            }
            return(this.manageTheText(keycode, cursorPos));
        },
        
        manageTheText: function(keycode, cursorPos){
          if(this.inputTextElement.value.length === 0){
              this.inputTextElement.value = this.viewMask;
          }
          cursorPos=this.skipMaskCharacters(keycode, cursorPos);
          if(cursorPos===false){
              return false;
          }
          if(this.injectValue(keycode, cursorPos)){
              this.moveCursorToPosition(keycode, cursorPos);
          }
          return(false);
        },
    
        processMaskFocus : function(){
            if(this.inputTextElement.value.length == 0){
                var cursorPos = this.getCursorPosition();
                this.inputTextElement.value = this.viewMask;
                this.moveCursorToPosition(null, cursorPos);
            }
        },
    
        isManagedByBrowser : function(keyEvent, keycode, type){
            if(((type=='keypress' && keyEvent.charCode===0) ||
                type=='keydown') && (keycode.unicode==Ext.EventObject.TAB ||
                keycode.unicode==Ext.EventObject.RETURN ||
                keycode.unicode==Ext.EventObject.ENTER ||
                keycode.unicode==Ext.EventObject.SHIFT ||
                keycode.unicode==Ext.EventObject.CONTROL ||
                keycode.unicode==Ext.EventObject.ESC ||
                keycode.unicode==Ext.EventObject.PAGEUP ||
                keycode.unicode==Ext.EventObject.PAGEDOWN ||
                keycode.unicode==Ext.EventObject.END ||
                keycode.unicode==Ext.EventObject.HOME ||
                keycode.unicode==Ext.EventObject.LEFT ||
                keycode.unicode==Ext.EventObject.UP ||
                keycode.unicode==Ext.EventObject.RIGHT ||
                keycode.unicode==Ext.EventObject.DOWN)){
                    return(true);
            }
            return(false);
        },
    
        handleEventBubble : function(keyEvent, keycode, type) {
            try {
                if(keycode && this.isManagedByBrowser(keyEvent, keycode, type)){
                    return true;
                }
                keyEvent.stopEvent();
                return false;
            } catch(e) {
                alert(e.message);
            }
        },
    
        getCursorPosition : function() {
            var s, e, r;
            if(this.inputTextElement.createTextRange){
                r = document.selection.createRange().duplicate();
                r.moveEnd('character', this.inputTextElement.value.length);
                if(r.text === ''){
                    s = this.inputTextElement.value.length;
                } else {
                    s = this.inputTextElement.value.lastIndexOf(r.text);
                }
                r = document.selection.createRange().duplicate();
                r.moveStart('character', -this.inputTextElement.value.length);
                e = r.text.length;
            } else {
                s = this.inputTextElement.selectionStart;
                e = this.inputTextElement.selectionEnd;
            }
            return this.CursorPosition(s, e, r, this.inputTextElement.value);
        },
    
        moveCursorToPosition : function(keycode, cursorPosition) {
            var p = (!keycode || (keycode && keycode.isBackspace ))? cursorPosition.start: cursorPosition.start + 1;
            if(this.inputTextElement.createTextRange){
                cursorPosition.range.move('character', p);
                cursorPosition.range.select();
            } else {
                this.inputTextElement.selectionStart = p;
                this.inputTextElement.selectionEnd = p;
            }
        },
    
        injectValue : function(keycode, cursorPosition) {
            if (!keycode.isDelete && keycode.unicode == cursorPosition.previousValue.charCodeAt(cursorPosition.start))
                return true;
            var key;
            if(!keycode.isDelete && !keycode.isBackspace){
                key=this.getValidatedKey(keycode, cursorPosition);
            } else {
                if(cursorPosition.start == cursorPosition.end){
                    key='_';
                    if(keycode.isBackspace){
                        cursorPosition.dec();
                    }
                } else {
                    key=this.viewMask.substring(cursorPosition.start,cursorPosition.end);
                }
            }
            if(key){
                this.inputTextElement.value = cursorPosition.previousValue.substring(0,cursorPosition.start)
                    + key +
                    cursorPosition.previousValue.substring(cursorPosition.start + key.length,cursorPosition.previousValue.length);
                return true;
            }
            return false;
        },
    
        getKeyCode : function(onKeyDownEvent, type) {
            var keycode = {};
            keycode.unicode = onKeyDownEvent.getKey();
            keycode.isShiftPressed = onKeyDownEvent.shiftKey;
            
            keycode.isDelete = ((onKeyDownEvent.getKey() == Ext.EventObject.DELETE && type=='keydown') || ( type=='keypress' && onKeyDownEvent.charCode===0 && onKeyDownEvent.keyCode == Ext.EventObject.DELETE))? true: false;
            keycode.isTab = (onKeyDownEvent.getKey() == Ext.EventObject.TAB)? true: false;
            keycode.isBackspace = (onKeyDownEvent.getKey() == Ext.EventObject.BACKSPACE)? true: false;
            keycode.isLeftOrRightArrow = (onKeyDownEvent.getKey() == Ext.EventObject.LEFT || onKeyDownEvent.getKey() == Ext.EventObject.RIGHT)? true: false;
            keycode.pressedKey = String.fromCharCode(keycode.unicode);
            return(keycode);
        },
    
        CursorPosition : function(start, end, range, previousValue) {
            var cursorPosition = {};
            cursorPosition.start = isNaN(start)? 0: start;
            cursorPosition.end = isNaN(end)? 0: end;
            cursorPosition.range = range;
            cursorPosition.previousValue = previousValue;
            cursorPosition.inc = function(){cursorPosition.start++;cursorPosition.end++;};
            cursorPosition.dec = function(){cursorPosition.start--;cursorPosition.end--;};
            return(cursorPosition);
        }
    };
    
    Ext.applyIf(RegExp, {
      escape : function(str) {
        return new String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
      }
    });
    
    Ext.ux.InputTextMask=Ext.ux.netbox.InputTextMask;
    And here is an example of the usage:
    Code:
    var dateTimeField = new Ext.form.TextField({plugins: [new Ext.ux.InputTextMask('99/99/9999 99:99', true)]});
    Enjoy!
    Last edited by bobbicat71; 4 Feb 2008 at 6:43 AM. Reason: latest version, opera support

  2. #2
    Sencha User krycek's Avatar
    Join Date
    Jun 2007
    Posts
    96
    Vote Rating
    0
    krycek is on a distinguished road

      0  

    Default


    I'm going to test it right now

  3. #3
    Sencha User krycek's Avatar
    Join Date
    Jun 2007
    Posts
    96
    Vote Rating
    0
    krycek is on a distinguished road

      0  

    Default


    It didn't work for me. I've tried on IE 6 and firefox 2.
    Here is how i used:
    Code:
     items: [{
                        xtype:'textfield',
                        fieldLabel: 'Name',
                        name: 'name',
    		    plugins: [new Ext.ux.InputTextMask('99/99/9999 99:99', true)],
                        anchor:'95%'
                    }, {...}
    Attached Images

  4. #4
    Ext User dandfra's Avatar
    Join Date
    Jun 2007
    Location
    Trento, Italy
    Posts
    122
    Vote Rating
    0
    dandfra is on a distinguished road

      0  

    Default


    It worked for me (IE6).
    Here's the code:
    PHP Code:
    <html>
    <
    head>
        <
    meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
        <
    title>Demo</title>
        <
    link rel="stylesheet" type="text/css" href="../../ext-2.0/resources/css/ext-all.css" />
        <
    script type="text/javascript" src="../../ext-2.0/adapter/ext/ext-base.js"></script>
        <script type="text/javascript" src="../../ext-2.0/ext-all-debug.js"></script>
        <script type="text/javascript" src="../src/InputTextMask.js"></script>
        <script>
    Ext.onReady(function(){
      var simple = new Ext.FormPanel({
            labelWidth: 75, // label settings here cascade unless overridden
            url:'save-form.php',
            frame:true,
            title: 'Simple Form',
            bodyStyle:'padding:5px 5px 0',
            width: 350,
            defaults: {width: 230},
            items: [{
                    fieldLabel: 'Date',
                    name: 'first',
                    xtype:'textfield',
                    plugins: [new Ext.ux.InputTextMask('99/99/9999 99:99', true)]
                }]
        });

        simple.render(document.body);
    });
    </script>
    </head>
    <body>
    </body>
    </html> 

  5. #5
    Sencha User krycek's Avatar
    Join Date
    Jun 2007
    Posts
    96
    Vote Rating
    0
    krycek is on a distinguished road

      0  

    Default


    It doesn't work when keyCode.unicode are between 97 and 120 (numeric keyboard)

  6. #6
    Sencha User krycek's Avatar
    Join Date
    Jun 2007
    Posts
    96
    Vote Rating
    0
    krycek is on a distinguished road

      0  

    Default


    I've changed processMaskFormatting to:
    Code:
     processMaskFormatting : function(e,type) {
            var keyCode = this.getKeyCode(e);
            if((type=='keydown' || type=='keypress') && ((keyCode.unicode >= 65 && keyCode.unicode <= 90) || (keyCode.unicode >= 97 && keyCode.unicode <= 122))){
                return true;
            }
    
            if(this.handleEventBubble(e, keyCode)){
                return true;
            }
            if(this.inputTextElement.value.length === 0){
                this.inputTextElement.value = this.viewMask;
            }
            var cursorPos = this.getCursorPosition();
            if(cursorPos.end == cursorPos.previousValue.length && !keyCode.isBackspace){
                return false;
            }
    
            while(this.specialChars.match(RegExp.escape(cursorPos.previousValue.charAt(((keyCode.isBackspace)? cursorPos.start-1: cursorPos.start))))){
                if(keyCode.isBackspace) {
                    cursorPos.decStart();
                } else {
                    cursorPos.incStart();
                }
                if(cursorPos.start >= cursorPos.previousValue.length || cursorPos.start < 0){
                    return false;
                }
            }
            if(keyCode.isBackspace){
                cursorPos.decStart();
            }
            if(this.injectValue(keyCode, cursorPos)){
                this.moveCursorToPosition(keyCode, cursorPos);
            }
            return false;
        },
    and It worked

  7. #7
    Sencha User krycek's Avatar
    Join Date
    Jun 2007
    Posts
    96
    Vote Rating
    0
    krycek is on a distinguished road

      0  

    Default


    As always, opera is the only browser that masks don't work

  8. #8
    Ext User
    Join Date
    Jul 2007
    Posts
    3,128
    Vote Rating
    1
    devnull is an unknown quantity at this point

      0  

    Default


    I had been working on this kind of functionality for Ext 1, but eventually gave up when I realized that it didnt allow for pasting into the field (and just about got sacked by my users because of it). I cant tell after taking a quick browse through your code, but does it handle pasting?

  9. #9
    Ext User bobbicat71's Avatar
    Join Date
    Dec 2007
    Location
    Italy
    Posts
    20
    Vote Rating
    1
    bobbicat71 is on a distinguished road

      0  

    Default


    Quote Originally Posted by krycek View Post
    It doesn't work when keyCode.unicode are between 97 and 120 (numeric keyboard)
    Thanks for the feedback. I have fixed my code to manage the numeric keypad.

  10. #10
    Ext User bobbicat71's Avatar
    Join Date
    Dec 2007
    Location
    Italy
    Posts
    20
    Vote Rating
    1
    bobbicat71 is on a distinguished road

      0  

    Default


    Quote Originally Posted by devnull View Post
    I had been working on this kind of functionality for Ext 1, but eventually gave up when I realized that it didnt allow for pasting into the field (and just about got sacked by my users because of it). I cant tell after taking a quick browse through your code, but does it handle pasting?

    Currently this feature is not implemented.
    I am looking for a solution to manage the copy paste.

Turkiyenin en sevilen filmlerinin yer aldigi xnxx internet sitemiz olan ve porn sex tarzi bir site olan mobil porno izle sitemiz gercekten dillere destan bir durumda herkesin sevdigi bir site olarak tarihe gececege benziyor. Sitenin en belirgin ozelliklerinden birisi de Turkiyede gercekten kaliteli ve muntazam, duzenli porno izle siteleri olmamasidir. Bu yuzden iste. Ayrica en net goruntu kalitesine sahip adresinde yayinlanmaktadir. Mesela diğer sitelerimizden bahsedecek olursak, en iyi hd porno video arşivine sahip bir siteyiz. "The Best anal porn videos and slut anus, big asses movies set..." hd porno faketaxi