I'm working on some javascript in a page with charset=utf8. We are hoping to limit certain input fields to numbers only. Someone showed me this code and it struck me that it refers to specific character codes which seems a little strange.

var restrictDollarToNum = function(e, source) {
  var restrictionType = /[1234567890.]/g;
  if (!e) e = window.event;
  if (e.keyCode) {
    code = e.keyCode;
  } else if (e.which) {
    code = e.which;
  }
  if (code >= 96 && code <= 105) {
    code -= 48;
  }
  var character = String.fromCharCode(code);
  if (!(character.match(restrictionType) || code == 8 || code == 13 || code == 46)) {
    source.value = source.value.replace(character, '');
    source.value = source.value.replace(character.toLowerCase(), '');
  } else {
    // maybe recaclulate something
  }
};

I was wondering a couple of things:
1) these keycodes -- do they refer to members of my charset or to key ordinals on my qwerty keyboard or something like that?
2) While this sort of thing may work on a US or UK english keyboard, might the codes be different on keyboards for other languages?
3) Is there perhaps a better way to do this?

    It's matching the keycode for the specific button on your keyboard, yes, but I'd be very surprised to hear of any good justifications for going about it this way.

    Rather than trying to intercept keycodes and translate their meaning, why not let the OS/browser do that and instead intercept the value of that keypress event?

      Thanks for the tip. I'll see if I can look into this shortly. It's very important that it works on all browsers. I know that event objects are defined differently in different browsers.

        sneakyimp;10998447 wrote:

        I know that event objects are defined differently in different browsers.

        How important is it to NOT use jQuery? If you used jQuery, you'd have one consistent event object across browsers. Moreover, you'd have an event object for anchor element events in all browsers rather than an event object for anchor elements in some browsers and event objects for window in IE on anchor events.

          I LOVE jquery and agree it would be useful. Unfortunately we are dealing with a really extensive custom JS framework and one of the parameters clearly laid down is that we will NOT use JQuery 🙁

            Do you know why? I'm simply curious. To me it seems like such a decision would do nothing but add 30-50&#37; development time to deal with browser inconsistencies. But sometimes sensible things seem insane to me, which is why I'm asking.

              12 days later

              Sorry to have been out of touch.

              The purported reason for not using JQuery in this context is that it 'adds a dependency' to the whole project. The project mgmt team wants to avoid any libraries which might need to be updated or which might slow down the porting of our code to a new server. PEAR, for instance, must be installed on a PHP server if you use PEAR, blah blah blah. I don't necessarily agree with this mentality, but I'm not the boss here.

              I'll see if I can come up with a better function here...

                OK I don't see any 'value' property of a keyup event -- or any other property for that matter -- which would allow me to run a cleanup function (or show a warning) or not. Seems to me the only way out here is just to do a pattern matching replacement on the input's contents on every single keyup.

                Here's my test page to inspect keyup events in firefox:

                <html>
                <head>
                <script type="text/javascript">
                document.addEventListener("DOMContentLoaded", function(){
                	var elt = document.getElementById("test");
                	if (!elt) alert('no elt');
                	elt.addEventListener("keyup", function(e) {
                		console.log(e);
                	});
                }, false);
                </script>
                </head>
                <body>
                  <input id="test" type="text" name="test" value="">
                </body>
                </html>

                  Here's a function which works -- just scrubs the input on every keyup. HOWEVER, one can always see the non-numeric key entered briefly before it gets deleted. I was hoping for something more instant. Any ideas?

                  // source is the htmlElement representing the input
                  // it is provided by the framework i'm working in.
                  var intsOnly = function(e, source) {
                    // we don't really care about the event, but it's convenient if we skip certain chars
                    if (!e) e = window.event;
                    if (e.keyCode) {
                      code = e.keyCode;
                    } else if (e.which) {
                      code = e.which;
                    }
                    // enter, backspace, delete
                    if (code == 8 || code == 13 || code == 46) return;
                  
                    source.value = source.value.replace (/[^\d]/g, "");
                  };
                  
                    sneakyimp;10999432 wrote:

                    The purported reason for not using JQuery in this context is that it 'adds a dependency' to the whole project. The project mgmt team wants to avoid any libraries which might need to be updated or which might slow down the porting of our code to a new server.

                    But adding jQuery would be more like a static library/link in that you could always distribute the jQuery framework .js file with the project itself.

                    One of the great features of jQuery is that it abstracts out some of the browser-specific differences for you. I would argue that including it wouldn't slow down porting, but actually increase the speed since you don't have to do hardly any work.

                    As for updating jQuery.. well you'd only need to do that if you want to pull in any of the changes that a newer version offers. I fail to see how that's any different than needing to update your own code (other than the fact that with jQuery, you'd simply download a new .js file and be done with it, whereas with your own code you have to spend hours/days developing and testing the new code yourself). Again, using jQuery makes updates faster.

                    So far, the score is 2-0 to jQuery. Any other justifications your (mis)management team came up with? :p

                    sneakyimp;10999440 wrote:

                    OK I don't see any 'value' property of a keyup event

                    The property you'd want is the "which" (or possibly "keyCode") property; this is the keycode of the key that drove the event.

                    Take a look at the jQuery .keyup() demo to get more information about these events.

                      bradgrafelman;10999445 wrote:

                      But adding jQuery would be more like a static library/link in that you could always distribute the jQuery framework .js file with the project itself.

                      Yes yes I know this. Were I the boss, I would be using jQuery like a boss. I love Jquery.

                      bradgrafelman;10999445 wrote:

                      The property you'd want is the "which" (or possibly "keyCode") property; this is the keycode of the key that drove the event.

                      Are you certain? That looks suspiciously like the keyCode to me. As you may recall, the original question in this post was about reliably getting the character associated with a keystroke. The 'which' that I've seen so far in the native firefox keyup event is always a number. E.g., if my keystroke is the lowercase f key on my US English keyboard, e.which = e.keyCode = 70. This doesn't match the ASCII code of lowercase F (which is 102 according to this chart) but does match the uppercase F ASCII code.

                      As it turns out, I'm triggering my function on every key stroke and it's a simle Javascript regex that replaces any non-digit characters with an empty string in the input -- so we don't really care about the code returned by the key in that case. I wonder if this would work for any character encoding?

                      My only real complaint is that waiting for the keyup to scour the input of non-digits is slow -- you see your typing in the input before they get wiped. I'm wondering if there's any way to speed this up? I tried keydown instead and also keydown+keyup but I couldn't effect any improvement.

                        If you want the actual ASCII value rather than the virtual keyCode, then try using the 'onkeypress' handler instead. The properties mentioned above should then correspond to the ASCII values of the character being entered into the textbox.

                        If you don't want to allow the character to be inserted into the textbox, try using an 'onbeforekeypress' handler instead and have it return false.

                        EDIT: Coincidentally, it sounds like what you're trying to do is exactly what this jQuery plugins was designed to do. Even if you can't use jQuery, perhaps you could look at the plugin's source to see how the author went about implementing it?

                          EDIT: Thanks for the helpful recommendations. This sounds promising.

                          I can't seem to find any documentation on "onbeforekeypress" -- a google search on it doesn't return anything remotely resembling official documentation about any "onbeforekeypress" event.

                          I've tried putting 'onbeforekeypress' and 'beforekeypress' as the event name in this test page, but those events never fire. "keypress" works, but returning false does nothing to prevent typing in the box:

                          <html>
                          <head>
                          <script type="text/javascript" src="NUI/jsonClass.js"></script>
                          <script type="text/javascript">
                          document.addEventListener("DOMContentLoaded", function(){
                          	var elt = document.getElementById("test");
                          	if (!elt) alert('no elt');
                          	elt.addEventListener("keypress", function(e) {
                          		console.log(e);
                          		if (!e) e = window.event;
                          		if (e.charCode) {
                          			var code = e.charCode;
                          			var s = String.fromCharCode(code);
                          			console.log("char = " + s);
                          			if (s.match(/\d/g)) {
                          				console.log("returning true");
                          				return true;
                          			} else {
                          				console.log("returning false");
                          				return false;
                          			}
                          		} else {
                          			throw "No charCode found!";
                          		}
                          	});
                          }, false);
                          </script>
                          </head>
                          <body>
                            <input id="test" type="text" name="test" value="">
                            <textarea id="output"></textarea>
                          </body>
                          </html>

                            Ignore that 'onbefore' crap - dunno what I was thinking. Somewhere in the back of my mind, I knew why I never use any of that 'onBefore' stuff... and then I suddenly remembered why: It's proprietary Micro$oft garbage.

                            As for the 'keypress' event not stopping the data from being entered... I was wrong about the 'return false' bit. You actually need to call the 'preventDefault' method on the event object. More info on that here.

                            Also note that while perusing the W3C page for the keypress event type, I noticed this:

                            W3C Working Draft wrote:

                            Warning! the keypress event type is defined in this specification for reference and completeness, but this specification deprecates the use of this event type in favor of the textinput event type.

                            So, I don't know how this complicates compatibility issues, but you may want to consider trapping textinput events instead(?).

                              Sorry to keep beating the jQuery horse, but it doesn't even need to be updated. You could just use the link provided by jquery.com for the latest release:

                              http://code.jquery.com/jquery-latest.min.js

                              It is possible however with this approach that a future release may remove or change functionality but jQuery is pretty good at keeping deprecated functionality working (for example their use of .on() and .off() for their events which replaced several functions).

                              Just something you might be able to pass to management.

                                Pointing to the "latest" copy is very very very bad and is never a good idea (unless we're talking about smaller projects that you don't really care about :p). jquery.com shouldn't be in charge of automatically upgrading (and/or breaking) your own libraries for your own projects. That's something that should be done manually by the developers once they've run through the gamut of system/regression testing against the newer library.

                                @: The recommendation to move to 'textInput' events actually seems to be both good and bad. It breaks compatibility, but it more closely matches what you're wanting to do.

                                For example, if you copy-and-paste text into an input field, no "keypress" event is fired. This makes sense; I pasted something into the field, I didn't press the keys on my keyboard to input the data manually. The 'textInput' event will be triggered regardless, though, since in the end you're still inputting text.

                                Another advantage is that there are no (key/char)codes to mess with - instead, the 'data' property should be a string containing the character(s) that was/were entered (copy-paste means you could insert several characters at once). Thus, you could do your regexp matching directly against that string to look for any unwanted characters.

                                EDIT: Example using the textInput event:

                                <html>
                                <head>
                                <script type="text/javascript">
                                document.addEventListener("DOMContentLoaded", function(){
                                	var elt = document.getElementById("test");
                                	if (!elt) alert('no elt');
                                	elt.addEventListener("textInput", function(e) {
                                		if (!e) e = window.event;
                                		if (e.data) {
                                			if (e.data.match(/[^\d]/g)) {
                                				console.log("returning false");
                                				e.preventDefault();
                                			}
                                		} else {
                                			throw "No data found!";
                                		}
                                	});
                                }, false);
                                </script>
                                </head>
                                <body>
                                  <input id="test" type="text" name="test" value="">
                                  <textarea id="output"></textarea>
                                </body>
                                </html>
                                  Bonesnap;10999453 wrote:

                                  You could just use the link provided by jquery.com for the latest release:

                                  Edit: Just realized I missed the second page entry above and brad allready pointed out how bad this is.

                                  <snip>

                                    But at least you wouldn't have to update it. 😉

                                      Write a Reply...