18 Replies Latest reply on Jul 29, 2013 7:00 AM by Michael L Hale

    Edittext and onChanging event

    Gustavo Del Vechio Level 3

      Hi friends

       

      I´m creating a dialog and one of the fields in this dialog should accept only numbers. So I thought I could use a combination of Regex and onChanging function with the edittex. Here´s the concept:

       

      var dlg = new Window ("dialog", "Test", undefined);

       

      var txt = dlg.add ("edittext", undefined, "");

      txt.characters = 40;

       

      txt.onChanging = function (){

         txt.text = txt.text.replace(/[^0123456789]/g, "");

      };

       

      dlg.show();

       

      With this code (it´s working) I´m sure user will not be able to type letters or anything else than numbers. But the problem is: if the user hits a letter in keyboard, then, after removing correctlly the letter, the function automatically inserts the pointer of the text in the beginning of such field..So, the next key user presses, it will be inserted in the beginning of the string. And it´s a problem when inserting the text.

       

      Is there any alternative (not necessary needs a regex) I could insert in the onChanging function, so the pointer of text always keep in the end of the field?

       

      If my explanation and question was confused, please tell I try to explain again

       

      Best Regards

      Gustavo.

        • 1. Re: Edittext and onChanging event
          Michael L Hale Level 5

          I think the best way to limit what is entered into an edittext control is to set up a keyboard handler. The Adobe script 'Fit Image' and 'Image Processor' has examples.

          • 2. Re: Edittext and onChanging event
            pixxxel schubser MVP & Adobe Community Professional

            You really need the onChanging-event?

             

             

            var dlg = new Window ("dialog", "Test", undefined);
            ar txt = dlg.add ("edittext", undefined, "");
            var txt2 = dlg.add ("edittext", undefined, "");
            txt.characters = 40;
            txt2.characters = 40;
            txt.onChange = function (){
            txt.text = txt.text.replace(/[^0-9]/g, "");
            }
            dlg.show();
            

             

            Perhaps you should try the onChange instead.

            • 3. Re: Edittext and onChanging event
              Michael L Hale Level 5

              I think using either onChange or onChanging to control what the user can enter into the control is less than ideal. With onChanging the use does get feedback that an incorrect char was entered but the text insertion is changed( as noted above). With onChange the user doesn't get any feedback  until the focus has changed to another control. I think onChange also has the problem that the user may not get the chance to correct the text or even know it was changed by the script. For example if the change in focus was because the user clicked on the 'run', 'ok', etc button.

               

              A keyboard event handler stops the incorrect char from being entered into the control. The user gets feedback and doesn't have to deal with a moving insertion point.

               

              function NumericEditKeyboardHandler (event) {
                  try {
                      var keyIsOK = KeyIsNumeric (event) || 
                                    KeyIsDelete (event) || 
                                    KeyIsLRArrow (event) ||
                                    KeyIsTabEnterEscape (event);
                                    
                      if (! keyIsOK) {
                          //    Bad input: tell ScriptUI not to accept the keydown event
                          event.preventDefault();
                          /*    Notify user of invalid input: make sure NOT
                              to put up an alert dialog or do anything which
                              requires user interaction, because that
                              interferes with preventing the 'default'
                              action for the keydown event */
                          app.beep();
                      }
                  }
                  catch (e) {
                      ; // alert ("Ack! bug in NumericEditKeyboardHandler: " + e);
                  }
              }
              //    key identifier functions
              function KeyIsNumeric ( event ) {
                  return  ( event.keyName >= '0' ) && ( event.keyName <= '9' ) && ! KeyHasModifier ( event );
              }
              function KeyHasModifier ( event ) {
                  return event.shiftKey || event.ctrlKey || event.altKey || event.metaKey;
              }
              function KeyIsDelete (event) {
                  //    Shift-delete is ok
                  return (event.keyName == 'Backspace') && ! (event.ctrlKey);
              }
              
              function KeyIsLRArrow (event) {
                  return ((event.keyName == 'Left') || (event.keyName == 'Right')) && ! (event.altKey || event.metaKey);
              }
              
              function KeyIsTabEnterEscape (event) {
                  return event.keyName == 'Tab' || event.keyName == 'Enter' || event.keyName == 'Escape';
              }
              function createDialog( ) {
                  var dlg = new Window( 'dialog', 'Example Dialog' );
                  dlg.maskSt = dlg.add( 'edittext', undefined, '' );
                  dlg.maskSt.preferredSize.width = 40;
                  dlg.maskSt.addEventListener ('keydown', NumericEditKeyboardHandler );
                 dlg.btnPnl = dlg.add( 'panel', undefined, 'Process' );
                 dlg.btnPnl.orientation = "row";
                 dlg.btnPnl.alignment = "right";
                 dlg.btnPnl.okBtn = dlg.btnPnl.add( 'button', undefined, 'Ok', { name:'ok' });
                 dlg.btnPnl.cancelBtn = dlg.btnPnl.add( 'button', undefined, 'Cancel', { name:'cancel' });
                 return dlg;
              };
              function initializeDialog( w ) {
                  w.maskSt.addEventListener ('keydown', NumericEditKeyboardHandler );
                  w.maskSt.onChanging = function() {
                                                  // range check if needed
                                                      if( Number(this.text) < 0 || Number(this.text) > 100 ){
                                                          alert('Out of range');
                                                          // handle however you like
                                                          this.text = '';
                                                      }
                                                  }
                  w.btnPnl.okBtn.onClick = function ( ) { this.parent.parent.close( 1 ); };
                  w.btnPnl.cancelBtn.onClick = function ( ) { this.parent.parent.close( 2 ); };
              };
              runDialog = function( w ) {
                 return w.show( );
              };
              var win = createDialog();
              initializeDialog( win );
              runDialog( win );
              
              • 4. Re: Edittext and onChanging event
                Gustavo Del Vechio Level 3

                Hi @pixxel

                 

                Thank you for the tip. At true, I always use the onChange event instead of onChanging. But I was looking for a "live" verification since, as Michael mentioned", onChange will validate the field only after pressing anyplace outside such field.

                 

                Michael, thank you very much for the example code. I was looking in the JavaScript Tools guide manual the features you wrote in the script in order to learn about it. I think I´m now understanding a little what have you done. To hard-test, I reduced your code into this (supposing the field should accept only the number 1):

                 

                function verify(event){

                    if (event.keyName == "1"){

                       alert("Great");

                    };

                    else{

                       event.preventDefault();

                    };   

                };

                 

                var dlg = new Window ("dialog", "Test", undefined);

                 

                var field = dlg.add ("edittext", undefined, "");

                field.characters = 20;

                 

                field.addEventListener ("keydown", verify);

                 

                dlg.show();

                 

                ---

                 

                A question. When you are writting in the field, sometimes it allows the other keys to be inserted. I perceived it also in your example. Is it expected to happen?

                 

                Thank you very much

                Gustavo.

                • 5. Re: Edittext and onChanging event
                  Michael L Hale Level 5

                  A question. When you are writting in the field, sometimes it allows the other keys to be inserted. I perceived it also in your example. Is it expected to happen?

                  No, that is not expected. The example I posted should only allow digits to be entered. And then only if the text, converted to number, is less than 100. That is the way it works for me and I can't get it to accept any other char.

                   

                  What other chars are you able to enter?

                   

                  BTW, as the comments in the code I posted noted, you can not use an alert in the event handler. For example with your code I do get the alert if I press 1 but it doesn't get entered into the control because of the alert.

                  • 6. Re: Edittext and onChanging event
                    Gustavo Del Vechio Level 3

                    Hi Michael

                     

                    The alert in my code was just to test if the handler was calling the function when I press 1 key. It´s not supposed to keep there.

                     

                    About the chars, it´s random. Try pressing faster various keys almost at the same time. Here it´s allowing some and blocking others!

                     

                    Are you able to reproduce this on your side?

                    • 7. Re: Edittext and onChanging event
                      JJMack Most Valuable Participant

                      Michael L Hale wrote:

                       

                      I think the best way to limit what is entered into an edittext control is to set up a keyboard handler. The Adobe script 'Fit Image' and 'Image Processor' has examples.

                      Mike I just noticed that the keyboard handler statements in CS6 Fit Image script have been commented out. So anything can be entered. You will get and error message if values ented are not numeric when you click OK. Do you know why?

                      • 8. Re: Edittext and onChanging event
                        Michael L Hale Level 5

                        I am not sure. I seem to remember a time that I couldn't get keyboard handlers to work with CS6. Maybe there was a bug so Adobe removed the handlers until they could get it fixed. But again, I really don't know why. Although I can't think of any good reason to comment out those lines unless they didn't work.

                        • 9. Re: Edittext and onChanging event
                          Michael L Hale Level 5

                          Are you able to reproduce this on your side?

                          No, I am not able to reproduce that. It could be you type much faster than I do but no matter how fast I try to enter chars it will not accept anything but digits. I guess it might also be a hardware difference( different keyboard or OS ).

                          • 10. Re: Edittext and onChanging event
                            pixxxel schubser MVP & Adobe Community Professional

                            @Michael L Hale,

                            great stuff. I tested this script today at work with CS6 on PC. It works perfect and it's a comfortable way. Only digits are allowed and no other chars. It changed always during the input - like you said.

                             

                             

                            (But it may be a little bit confusing for some users not to get the complete input as output.) That's why I prefer the onChange-method with an (stupid) alert, if the input is not correct. (Pssst: EIFOK-conform)

                            • 11. Re: Edittext and onChanging event
                              Michael L Hale Level 5

                              Like most tasks in Photoshop there are different ways to get the same end results. I am not trying to say one way is better, just that I prefer using keyboard event handlers to limit input of a dialog control. I think the beep is good feedback of an unwanted char. Of course it is better if the dialog has other elements to guide the users such as labels and helptext.

                               

                              It is easy to extend the handler function to limit for other types of input. For example I have made functions that limit to just alpha chars, positive and negative integers, floating point numbers, etc. I even have a function that only accepts valid hex chars.

                               

                              I also think that no matter what method is used is better to have checks after the user closes the dialog that make sure there is valid data from the dialog before the script uses that data.

                               

                              By the way, I can't take credit for this method. I just borrowed it from some of the Adobe scripts.

                              • 12. Re: Edittext and onChanging event
                                DBarranca Level 4

                                Interesting discussion!

                                Personally I've been using onChanging() callbacks for allowed/forbidden chars (but now I see the appeal of the keyboard event handler), and onChange() for validating the text field, as in the following example:

                                (it's coffeescript and not JS - nice, concise syntax! - I'll put the compiled JS afterwards, the example is for a Radius-like edit text so real positive numbers with 2 decimals)

                                 

                                    win.darkPanel.darkRadiusGroup.darkRadiusText.onChanging = () ->
                                        # Digits and "." only
                                        if @text.match(/[^0-9.]/) then @text = @text.replace(/[^0-9.]/g,'')
                                        return
                                        
                                    win.darkPanel.darkRadiusGroup.darkRadiusText.onChange = () ->
                                        # .2 becomes 0.2
                                        if @text.charAt(0) is '.' then @text = "0#{@text}"
                                        
                                        # Strips 000 before number, let 0 if 0.2
                                        @text = @text.slice(1) while @text.charAt(0) is "0" and @text.charAt(1) isnt "."
                                        
                                        # Forbids 2.2.2, etc.
                                        if @text.match(/^\d{0,3}\.?\d/) isnt null or @text.match(/^\d{0,3}\.?\d/) isnt ""
                                            @text = @text.match(/^\d{0,3}\.?\d/)
                                        
                                        # not bigger than 250
                                        if @text > 250 then @text = 250
                                        
                                        if @text is 'null' or @text is ''
                                            @text = darkRadiusDefault
                                

                                 

                                which in JS becomes:

                                 

                                win.darkPanel.darkRadiusGroup.darkRadiusText.onChanging = function() {
                                  if (this.text.match(/[^0-9.]/)) {
                                    this.text = this.text.replace(/[^0-9.]/g, '');
                                  }
                                };
                                
                                win.darkPanel.darkRadiusGroup.darkRadiusText.onChange = function() {
                                  if (this.text.charAt(0) === '.') {
                                    this.text = "0" + this.text;
                                  }
                                  while (this.text.charAt(0) === "0" && this.text.charAt(1) !== ".") {
                                    this.text = this.text.slice(1);
                                  }
                                  if (this.text.match(/^\d{0,3}\.?\d/) !== null || this.text.match(/^\d{0,3}\.?\d/) !== "") {
                                    this.text = this.text.match(/^\d{0,3}\.?\d/);
                                  }
                                  if (this.text > 250) {
                                    this.text = 250;
                                  }
                                  if (this.text === 'null' || this.text === '') {
                                    return this.text = darkRadiusDefault;
                                  }
                                };
                                

                                 

                                Regards

                                 

                                Davide Barranca

                                www.davidebarranca.com

                                • 13. Re: Edittext and onChanging event
                                  xbytor2 Level 4

                                  Just to add my 2 cents...

                                   

                                  Prior to writing ContactSheetII for CS6, I had always used onChanging with RegExps for keystroke filtering. It has it's problems, as mentioned above, but I could live with that.

                                   

                                  For ContactSheetII, Adobe couldn't live with that, so I used addEventListener('keydown', ...); code like Mike describes above.

                                  The key was getting the callback function just right.

                                   

                                  ContactSheetUI.filterKey = function(event) {
                                    var obj = event.currentTarget;
                                    var filter = obj.keyFilter;
                                  
                                    var c = Number("0x" + event.keyIdentifier.substring(2));
                                    var key = String.fromCharCode(c);
                                  
                                    // $.writeln(event.keyName + ' : ' + key + ' : ' + filter);
                                  
                                    if (filter && key.match(filter)) {
                                      return;
                                  
                                    } else if (event.keyName == 'Enter') {
                                      ContactSheetUI.handleEnterKey(event);
                                  
                                    } else if (event.keyName.length == 1) {
                                      event.stopPropagation();
                                      event.preventDefault();
                                    }
                                  };
                                  

                                   

                                  obj.keyFilter would be set to a RegExp on the UI widget beforehand. The ContactSheetUI.handleEnterKey function is there because CSII needs to validate the field before allowing the EnterKey to propagate up the stack to where it would eventually invoke the OK button. If the field is invalid, the propagation is stopped and the EnterKey is eaten.

                                  • 14. Re: Edittext and onChanging event
                                    Gustavo Del Vechio Level 3

                                    Michael said:

                                    I guess it might also be a hardware difference( different keyboard or OS ).

                                     

                                    No, I found what´s happened. I made another test

                                     

                                    I´ve just tested again with your code and even my code. If I run directlly as test in Extended Script (without targetting any application), and if I type fast, it allows some characters like I mentioned earlier.

                                     

                                    BUT, if I #target photoshop and execute (sure, inside Photoshop), then it´s PERFECT. No matter how fast I type. It really allows only numbers.

                                     

                                    Perhaps a bug in Extended Script testing´s engine?

                                     

                                    Gustavo.

                                    • 15. Re: Edittext and onChanging event
                                      Michael L Hale Level 5

                                      I have learned over the years if you want to test a Photoshop dialog you have to test either with Photoshop or in ESKT with Photoshop as the target. Even some of the Adobe ScriptUI examples behave differently in ESTK than they do in Photoshop. There are some ScriptUI features that work in ESTK that don't work at all in Photoshop.

                                       

                                      So yeah, I didn't test without Photoshop being the target app and didn't notice that behavior.

                                       

                                      I am not sure if it's a bug. As I understand it each product team handles ExtendScript for thier product. It may just be a difference between how the different teams handled that feature.

                                      • 16. Re: Edittext and onChanging event
                                        Gustavo Del Vechio Level 3

                                        Yeah, completelly right!

                                        • 17. Re: Edittext and onChanging event
                                          DBarranca Level 4

                                          Mike,

                                          I was reviewing your code - could you please explain why the eventListener is set in two different places (while creating the dialog and while initializing)?

                                          Thank you!

                                           

                                          Davide

                                          • 18. Re: Edittext and onChanging event
                                            Michael L Hale Level 5

                                            My guess is that it's a cut and paste mistake when I put this together. The eventListener only needs to be set once. I would remove it from createDialog.