...

View Full Version : Keypress capitalize function broken in IE9



softwaredev34
10-10-2011, 04:35 PM
A common javascript function that capitalizes input as user types (onkeypress) no longer works as of IE9. Need a function that also works in IE 9 that doesn't not change method call or interface (as it's used in 150 places throughout application).


CALL:
[CODE]
el.onkeypress = function(el) {
return c_capitalizeInput(el);
}
[CODE]
FUNCTION:
[CODE]
// Intercepts keyboard input and capitalizes keystrokes.
// Call with onkeypress="return capitalizeInput(event);"
// Compatible with both IE and Netscape/Mozilla
function c_capitalizeInput(evt) {
evt = (evt) ? evt : ((window.event) ? window.event : "");
if (window.event) {
// IE
if ((evt.keyCode >= 97) && (evt.keyCode <= 122)) {
evt.keyCode = evt.keyCode - 32;
}
return true;
} else if (evt.which) {
// Netscape and Mozilla
key = evt.which;
if ((key >= 97) && (key <= 122)) {
key = key - 32;
evt.target.value = evt.target.value + String.fromCharCode(key);
return false;
}
return true;
} else {
return true;
// Can't do anything for other browsers
}
}
[CODE]

Any suggestions to make this work in IE9?

blaze4218
10-10-2011, 04:41 PM
This usually does the trick for me...

<input type="text" onkeyup="this.value=this.value.toUpperCase()" />

softwaredev34
10-10-2011, 04:50 PM
That would be ideal if starting from scratch, but need to replace existing method that is widely used. Also, triggered by keypress . .

blaze4218
10-10-2011, 04:51 PM
I think this is what your looking for though:



<script>
el.onkeyup = function(){
el.value=el.value.toUpperCase()
}
</script>

If el is what I think then you should just be able to insert that to replace what you already have...

blaze4218
10-10-2011, 04:52 PM
I find that keyup is usually preferable for me, but if you need keypress you would just replace the "keyup" with "keypress"

Edit:
I wouldn't recommend that though, I just tested it, and it's one character behind if you opt for keypress... keyup really is better...

blaze4218
10-10-2011, 04:58 PM
At the end of the day, I find that keypress just isn't as reliable. It often doesn't give me the results that I anticipate. But honestly, there's no reason you couldn't just do this:



<script>
el.onkeypress = function(){
el.value=el.value.toUpperCase()
}
el.onkeyup = function(){
el.value=el.value.toUpperCase()
}
</script>

DaveyErwin
10-10-2011, 05:17 PM
I agree with Blaze that toUpperCase
is a reasonable solution but this
works everywhere I think ....


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta name="generator" content="daveyerwin">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>SJax</title>
<script type="text/javascript">
function c_capitalizeInput(evt) {
evt=evt||event;
key=evt.which||evt.keyCode;
target=evt.target||evt.srcElement;
if ((key >= 97) && (key <= 122)) {
key = key - 32;
target.value = target.value + String.fromCharCode(key);
return false;
}
}
function init(){
document.getElementById("inTxt").onkeypress=c_capitalizeInput;
}
</script>
</head>
<body onload="init()">
<div id="container">
<p><input type="text" id="inTxt"></p>
</div>
</body>
</html>

venegal
10-10-2011, 05:29 PM
That original code works in NO modern browser, except Firefox. Not Safari, not Chrome, not Opera, not IE9.

That "Netscape" comment kind of gives it away that that code is ancient.

blaze4218's suggestion will probably do what you want, if you make some changes to actually make it work with the keypress event:


el.onkeypress = function () {
var self = this;
setTimeout(function () {
self.value = self.value.toUpperCase();
}, 0);
};


keypress isn't "unreliable" this is just a matter of execution order: It will do its thing before the input value is actually updated, so it's able to prevent key presses. Just use a setTimeout 0 to delay the action until the browser has become idle.

Anyway, you have to be aware that, depending on what you are actually trying to accomplish here, that whole approach might be flawed: What if someone pastes text using their mouse? What if they have Javascript disabled?

Those questions might be irrelevant, if this is for display purposes only. In that case, though, it's much better to just use the CSS property text-transform: uppercase.

If, on the other hand, you're expecting uppercase input on the server, then you have to validate it there anyway, so just uppercase it there instead of hacking around on the client side.

blaze4218
10-10-2011, 05:36 PM
"I find that keypress just isn't as reliable" was meant as an opinion, not fact. I thought I cleared that up with "doesn't give me the results that I anticipate"...
Doing it's thing before the input value is updated is the problem of which I spoke. If I misrepresented opinion as fact I apologize.

venegal
10-10-2011, 05:48 PM
"I find that keypress just isn't as reliable" was meant as an opinion, not fact. I thought I cleared that up with "doesn't give me the results that I anticipate"...
Doing it's thing before the input value is updated is the problem of which I spoke. If I misrepresented opinion as fact I apologize.

Something not being reliable means to me that it sometimes works and sometimes fails, without any apparent reasons for the failures, which usually points to either a race condition or to not having understood the failure scenario very well so I just wanted to clear up what it actually does; there's no need to apologize.

softwaredev34
10-10-2011, 08:14 PM
The onkeypress solution with the timeout (venegal) worked in some cases. . . but not in every case. I wanted to go this route because I didn't want to change the method call to onkeyup each time it was used.

Here is the situation:

It works when the function is called like either of these:a)

onkeypress="return c_capitalizeInput(this);"

b)

function(el) {
el.onkeypress = function() {
return c_capitalizeInput(el)
}
}



It does not work when it is called like either of these:
a)

onkeypress="return c_capitalizeInput(event);"

b)

function(el) {
el.onkeypress = function(el) {
return c_capitalizeInput(el)
}
}

softwaredev34
10-10-2011, 08:16 PM
DaveyErwin, I had tried the same solution as well . . . and was happy with how it worked until I realized that the maxlenth was no longer obeyed. This had always been true for Firefox, but now was also apparent in IE.

venegal
10-11-2011, 01:14 AM
The onkeypress solution with the timeout (venegal) worked in some cases. . . but not in every case.

Does that mean that among those 150 calls, all of those 4 cases you listed are actually implemented? The code I posted relies on this referring to the input element, but if you have no control over what this will actually be, it won't do you any good.

If DaveyErwin's code works for you, you can just go with that all you have to do is add a target.maxlength check to the part where you concatenate to target.value.

It's still flawed, though, like I mentioned in my first post, and I'd still recommend using CSS or a server side filter (or both), depending on what you are actually trying to accomplish here.

Logic Ali
10-11-2011, 03:19 AM
Include this once in each involved document, as-is or as a .js file.

No configuration required.


<script type="text/javascript">

(function()
{
/* Capitalise typed content of all text inputs and textareas unless "noCaps" is part of their 'class' attribute */

function installHandler( obj, evt, func )
{
window.attachEvent ? obj.attachEvent( evt, func ) : obj.addEventListener( evt.replace(/^on/i, ""), func, false );
}

installHandler( document, 'onkeyup', function( e )
{
var evt = e || window.event,
srcElem = evt.target || evt.srcElement;

if( !srcElem.className.match( /\bnoCaps\b/ ) && ( srcElem.nodeName == 'TEXTAREA' || ( srcElem.nodeName == 'INPUT' && srcElem.type == 'text' ) ) )
srcElem.value = srcElem.value.toUpperCase();

} );

})( /*2843294C6F67696320416C69*/ );

</script>

softwaredev34
10-13-2011, 03:43 PM
For the common method, c_capitalizeInput(el), I was able to update the function to be backward compatible with the following:




function c_capitalizeInput(evt) {

// use the value of event if available
// if not assume it's IE and use window.event
evt=evt||window.event;

//return keycode in Firefox or IE
key=evt.which||evt.keyCode;

//return target element in Firefox or IE
target=evt.target||evt.srcElement;

//check to see if the key that was pressed is a lowercase letter
if ((key >= 97) && (key <= 122)) {
//subtract 32 to get uppercase value
key = key - 32;
//only append value if maxlength not exceeded
if (target.maxLength > target.value.length){
//append uppercase value to existing value
target.value = target.value + String.fromCharCode(key);
}
return false;
}
return true;

}



However, the behavior was still less than perfect because any highlighted data in the field was either appended to or not replaced (if at the maxlength). Therefore, I deprecated this method.

Going forward, the following method will be used.



function c_upper(el){
el.value=el.value.toUpperCase()
}

softwaredev34
10-14-2011, 03:15 PM
This last approach doesn't do the trick either!



function c_upper(el){
el.value=el.value.toUpperCase()
}


It introduces strange cursor behavior where the cursor jumps to the end of the text after typing.

Does anyone know of a solution that will retain the cursor position and uppercase as the user types?

blaze4218
10-14-2011, 04:07 PM
You know, it never really occurred to me that you would be editing a text field. My assumptions were that you would be appending, and so I never really thought about that being problematic... Oops...

You could incorporate the following to get the caret position before you uppercase, then set the position to what it previously was...


function c_upper(el){
var caret_position = getCaretPosition(el)
el.value=el.value.toUpperCase()
setCaretPosition(el, caret_position)
}

//http://stackoverflow.com/questions/512528/set-cursor-position-in-html-textbox
function getCaretPosition (ctrl) {
Removed: Incorrect output
}


function setCaretPosition(ctrl, pos)
{

if(ctrl.setSelectionRange)
{
ctrl.focus();
ctrl.setSelectionRange(pos,pos);
}
else if (ctrl.createTextRange) {
var range = ctrl.createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
}
}

blaze4218
10-14-2011, 04:20 PM
You know what? that getCaretPosition is off, try this:


function c_upper(el){
var caret_position = getCaretPosition(el)
el.value=el.value.toUpperCase()
setCaretPosition(el, caret_position)
}

//http://stackoverflow.com/questions/512528/set-cursor-position-in-html-textbox
function getCaretPosition (el) {

if (el.selectionStart) {
return el.selectionStart;
} else if (document.selection) {
el.focus();

var r = document.selection.createRange();
if (r == null) {
return 0;
}

var re = el.createTextRange(),
rc = re.duplicate();
re.moveToBookmark(r.getBookmark());
rc.setEndPoint('EndToStart', re);

return rc.text.length;
}
return 0;

}


function setCaretPosition(ctrl, pos)
{

if(ctrl.setSelectionRange)
{
ctrl.focus();
ctrl.setSelectionRange(pos,pos);
}
else if (ctrl.createTextRange) {
var range = ctrl.createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
}
}

Sorry, that was from stack overflow, but I got a different getCaretPosition function and tested it this time :o

softwaredev34
10-14-2011, 04:25 PM
Thanks so much for your help . . . . one slight issue still remains . . . the maxlength is no longer obeyed.

blaze4218
10-14-2011, 04:30 PM
Have you tried limiting your form manually?


function limitText(limitField, limitNum) {
if (limitField.value.length > limitNum) {
limitField.value = limitField.value.substring(0, limitNum);
}
}



function c_upper(el){
var caret_position = getCaretPosition(el);
el.value=el.value.toUpperCase();
setCaretPosition(el, caret_position);
limitText(el, 500);
}


Edit:
I would like to note that this is best applied to a textarea that is being appended. If you edit within the textarea then your input will be allowed, but the end of the input will be truncated. If you would like to prevent further input instead of truncating you might try something to suppress the input.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum