8 Replies Latest reply on Mar 24, 2016 7:38 AM by Sturm359

    Immediate change to Text Field's character limit?

    Sturm359 Level 1

      I have a PDF form that I am trying to make more foolproof. As a user enters their credit card number, I want it to check the first two digits to see which kind of card it is (Visa/MasterCard/American Express) and select the appropriate radio button for them, as well as limit the number of digits that can be entered in that credit card number field. I have it mostly figured out, but it seems that changing the character limit (charLimit) of the Card Number field doesn't actually take place until the focus leaves the field, then re-enters it. Here's the code I have so far, in the Custom Keystroke Script property on the Format tab of that field:

       

      event.rc = /^\d*$/.test(event.change);
      
      
      var thisField = event.target;
      var amexTest = /^3[47]/;
      var mcTest = /^5[1-5]/;
      var visaTest = /^4/;
      var firstTwo = event.value.slice(0,2);
      var ccButtons = getField("Credit Card Buttons");
      if (amexTest.test(firstTwo)) {
          thisField.charLimit = 15;
          ccButtons.value = "AMEX";
      } else if (mcTest.test(firstTwo)) {
          thisField.charLimit = 16;
          ccButtons.value = "Master Card";
      } else if (visaTest.test(firstTwo)) {
          thisField.charLimit = 19;
          ccButtons.value = "Visa";
      }
      

       

      It looks like my pasted code got a little cut off toward the end for some reason, but I think that's enough to show what I want to have happen. Because this script runs at every keystroke, then after the first two characters are typed, I want it to limit the number of characters to what is appropriate for that type of card. This should help a bit in having people mis-type their number. However, as I said, the change doesn't actually take place until the focus leaves and re-enters that field.

       

      What can I do to make the change immediate?

        • 1. Re: Immediate change to Text Field's character limit?
          try67 MVP & Adobe Community Professional

          I don't think you can't do it like that, but you don't need to. Since you're already using a script for the Keystroke event you can check the length of the full text and then reject the keystroke if it's too long.

          • 2. Re: Immediate change to Text Field's character limit?
            Sturm359 Level 1

            Okay, I see where you are going with this, but I'm having trouble figuring out the exact line of code that would be necessary for it. I'm close with this:

             

            event.rc = event.value.length < 15 || !/^[\w\s]*$/.test(event.change);
            
            

             

            Placing that in the if (amexTest.test(firstTwo)) condition, after the ccButtons.value = "AMEX"; line doesn't quite seem to work. Neither the [DELETE] nor [BACKSPACE] keys work once the limit has been reached. Also, when the focus changes away from the field, the entire field is emptied. Definitely not what I want. I'm sure I have to find some way of using event.willCommit, but I do not know how. Thoughts?

            • 3. Re: Immediate change to Text Field's character limit?
              try67 MVP & Adobe Community Professional

              You need to use AFMergeChange(event) to get access to the full new value of the field. event.value will only return the value before the current keystroke, which is not what you want. I'm also not sure about your regular expression. What are you trying to do there, exactly?

              • 4. Re: Immediate change to Text Field's character limit?
                Sturm359 Level 1

                I'll have to research AFMergeChange(event). In the mean time, I actually got it all working as I wanted it to, by simply adding together .value and .change, thusly:

                 

                var digitsOnly = /^\d*$/;
                event.rc = digitsOnly.test(event.change);
                
                
                var thisField = event.target;
                var amexTest = /^3[47]/;
                var mcTest = /^5[1-5]/;
                var visaTest = /^4/;
                var allText = event.value + event.change;
                var firstTwo = allText.slice(0,2);
                var ccButtons = getField("Credit Card Buttons");
                if (amexTest.test(firstTwo)) {
                    ccButtons.value = "AMEX";
                    event.rc = (allText.length <= 15 && digitsOnly.test(event.change)) || !/^[\w\s]*$/.test(event.change);
                } else if (mcTest.test(firstTwo)) {
                    ccButtons.value = "Master Card";
                    event.rc = (allText.length <= 16 && digitsOnly.test(event.change)) || !/^[\w\s]*$/.test(event.change);
                } else if (visaTest.test(firstTwo)) {
                    ccButtons.value = "Visa";
                    event.rc = (allText.length <= 19 && digitsOnly.test(event.change)) || !/^[\w\s]*$/.test(event.change);
                }
                if (!event.rc) {
                    app.beep();
                }
                

                 

                As for the regex in each case, the idea is to filter out all keystrokes once the character limit has been reached except for the delete or backspace keys. Thus allowing for the text to be replaced in case the user typed in the wrong number and needs to change it. It may not be necessary anymore now that I've added in the digitsOnly test, but I've run out of time today to find out. Perhaps tomorrow. Thanks for your help, try67!

                • 5. Re: Immediate change to Text Field's character limit?
                  try67 MVP & Adobe Community Professional

                  This is a built-in, undocumented function that merges the old value with the new one correctly. You should use it instead of your makeshift version of it because it handles deletions, insertions in all locations, pasting text and other kinds of edits correctly.

                  • 6. Re: Immediate change to Text Field's character limit?
                    Sturm359 Level 1

                    Sounds nice, but I'm afraid it breaks everything. When I replace the line

                     

                    var allText = event.value + event.change;
                    

                     

                    with

                     

                    var allText = AFMergeChange(event);
                    

                     

                    And click [OK], my Custom Formatting and Keyboard scripts disappear entirely: The Select format category dropdown changes from Custom to None, so my scripts are lost.

                    Even if I just put that phrase in a comment, such as

                     

                    // AFMergeChange(event);
                    

                     

                    The dropdown changes to None when I hit [OK].

                    • 7. Re: Immediate change to Text Field's character limit?
                      Karl Heinz Kremer Adobe Community Professional

                      This is unfortunately how Acrobat works: if it recognizes certain internal names, it assumes (wrongly) that the JavaScript was generated by you using one of the predefined formats. The way around this is to create a document level function that calls the AF... function (this is not just limited to AFMergeChange), and then call that document level function from your format or keystroke event handler.

                      • 8. Re: Immediate change to Text Field's character limit?
                        Sturm359 Level 1

                        Sheesh, so many nuances to Acrobat that I never knew of. Undocumented functions that are better than hand-written ones, making assumptions and erasing days of work without so much as a warning. What a mess.

                         

                        Nevertheless, your suggestion did work, Karl Heinz Kremer, thank you. I now have a document script:

                         

                        function getMergedText(event) {
                            return AFMergeChange(event);
                        }
                        

                         

                        To go along with my form field's script:

                         

                        var digitsOnly = /^\d*$/;
                        event.rc = digitsOnly.test(event.change);
                        
                        
                        var thisField = event.target;
                        var amexTest = /^3[47]/;
                        var mcTest = /^5[1-5]/;
                        var visaTest = /^4/;
                        var allText = getMergedText(event);
                        var firstTwo = allText.slice(0,2);
                        var ccButtons = getField("Credit Card Buttons");
                        if (amexTest.test(firstTwo)) {
                            ccButtons.value = "AMEX";
                            event.rc = allText.length <= 15 && digitsOnly.test(event.change);
                        } else if (mcTest.test(firstTwo)) {
                            ccButtons.value = "Master Card";
                            event.rc = allText.length <= 16 && digitsOnly.test(event.change);
                        } else if (visaTest.test(firstTwo)) {
                            ccButtons.value = "Visa";
                            event.rc = allText.length <= 19 && digitsOnly.test(event.change);
                        } else if (allText.length < 1) {
                            ccButtons.value = null;
                        }
                        if (!event.rc) {
                            app.beep();
                        }
                        

                         

                        I also have added in a format script so when the user changes focus to a different field, the credit card number is automatically formatted to look a tad nicer:

                         

                        event.value = event.value.slice(0,4)
                                        + " " + event.value.slice(4,8)
                                        + " " + event.value.slice(8,12)
                                        + " " + event.value.slice(12);
                        

                         

                        And lastly, make sure the three radio buttons next to the credit card choices are emptied when the document is opened (unless a card number exists, of course):

                         

                        if (getField("Card Number").value.length < 1) {
                            getField("Credit Card Buttons").value = null;
                        }
                        

                         

                         

                        And that's it! Yeah, it's probably a bit kludgy and could be coded more efficiently, but at least it works, thanks to your help! Now I just need to decide who gets the credit for the "Correct Answer." :~)