|
Don't Forget Paste Validation
In the preceding step, you made sure that the paste command would still work. The problem is that pasting a value into the textbox bypasses the normal keypress event, so users can enter an illegal string. To test this behavior, try Example 6b again. Highlight the text above the textbox and copy it to the clipboard. Then, click on the textbox and paste from the clipboard. Congratulations, you've just pasted letters into the number-only textbox.
You can't just worry about someone who presses Ctrl + V either. Remember, someone can paste by right clicking on the textbox and selecting Paste from the popup menu. To solve this problem, you must investigate browser-by-browser.
In NS4, here's the bad news: you can't block a paste. It just isn't possible with the NS4 object model. So the only alternative is to check the value of the textbox periodically to be sure that the user hasn't pasted in any illegal values. I prefer to do this using the onchange event handler. You might ask: "Why not do it on the onblur event handler?" The answer is: The change event occurs only when a control has both lost focus and its value has changed, while the blur event fires anytime the textbox loses focusregardless of whether the value has changed.
The function called isValid() checks to see if the textbox contents are valid. The check requires another regular expression:
var reValidString = /^\d*$/;
This regular expression specifies that any number of digits may appear between the start (^) and end ($) of the string. Here's the code to check the value:
function isValid(strValue) {
return reValidString.test(strValue) ||
strValue.length == 0;
}
Note that the value is valid if it has a length of zero (the onsubmit event handler should determine whether a field is required). Also note that you can change this function to use any other validity check that you deem reasonable for masking other types of data.
The overall behavior you want is this: when the textbox loses focus, check the value. If the value isn't a number, display an error notification. You want to return the textbox to the last known valid value (it's never a good idea to leave an illegal value in a textbox). Finally, shift the focus back to the textbox and highlight the text inside.
The maskKeyPress() function is a good place to store the last valid value for the textbox, because it's the first line of defense against illegal values. You need to modify this function so that it gets a reference to the textbox and stores the value if it is valid. The event object provides the reference. In IE, use the event.srcElement property to get the reference; in NS4 and NS6 use the event.target property.
Now, you want to store the last valid value for the textbox just before checking the pressed key. Why? Because the value of the textbox while executing this function does not include the pressed key, so the textbox contents should be valid. First, check to see if the current value in the textbox is valid. If it is, then store the valid value and continue with normal processing. If not, prevent the key press, inform the user there is an invalid value in the textbox, and reset the contents to the last valid value:
function maskKeyPress(objEvent) {
var iKeyCode, strKey, objInput;
if (isIE) {
iKeyCode = objEvent.keyCode;
objInput = objEvent.srcElement;
} else {
iKeyCode = objEvent.which;
objInput = objEvent.target;
}
strKey = String.fromCharCode(iKeyCode);
if (isValid(objInput.value)) {
objInput.validValue = objInput.value;
if (!reValidChars.test(strKey) &&
!reKeyboardChars.test(strKey) &&
!checkClipboardCode(objEvent, strKey)) {
alert("Invalid Character Detected!\nKeyCode = "
+ iKeyCode + "\nCharacter =" + strKey);
return false;
}
} else {
alert("Invalid Data");
return false;
}
}
A problem with this method is that the value in the textbox does not yet include the key that was pressed. You can't simply add the new character to the end of the textbox contents, because the user may be typing into the middle of the textbox. So, your validation is one character behind the valid value, which is why you also store the valid value during the change event.
The maskChange() function checks the validity of the current textbox value. If it is invalid, an alert will pop up, the textbox will revert back to its last known valid value (or an empty string if no valid value has been stored yet), resets the focus to the textbox, and highlights the text. If the value is valid, the function stores the new valid value for later use:
function maskChange(objEvent) {
var objInput;
if (isIE)
objInput = objEvent.srcElement;
else
objInput = objEvent.target;
if (!isValid(objInput.value)) {
alert("Invalid data");
objInput.value = objInput.validValue || "";
objInput.focus();
objInput.select();
} else {
objInput.validValue = objInput.value;
}
}
I included the check for IE because validating a textbox onchange is a good idea no matter which browser you have. The next step of implementing an onchange validation is to specify the event handler in the input tag:
<input type="text" name="txtExample"
onkeypress="return maskKeyPress(event)"
onchange="maskChange(event)">
Note that the onchange event handler doesn't return the value of the maskChange() function. Thats's because you don't want to cancel the change event; you just want to validate when it occurs. Example 7a sports the new validation.
To sum up: In NS4, if a user pastes an invalid value and then (without changing focus to a different textbox) types in a valid value, the textbox does not contain a valid value. The only way to prevent this is to check the value of the textbox whenever the user presses a key.
Now that you have somewhat solved the paste problem in NS4, it's much simpler to solve it for IE, because form controls in IE have a paste event. When you specify an onpaste event handler, you can actually cancel the paste! The paste event fires when the user presses Ctrl + V and when the user clicks Paste from the context menu. Better yet, the kind folks at Microsoft provided IE with the ability to look into the clipboard to see what's there. The window.clipboardData object has a getData() method. By specifying the type of data you're looking for as "Text" in the getData() method, you can see the text that the user is about to paste into the textbox (you don't need to worry about images being pasted). First, retrieve the text from the clipboard and then test using the same isValid() function used previously. If the text is not valid, alert the user that an error occurred, set the focus back to the textbox, and cancel the paste (return false from the onpaste event handler):
function maskPaste(objEvent) {
var strPasteData = window.clipboardData.getData("Text");
var objInput = objEvent.srcElement;
if (!isValid(strPasteData)) {
alert("Invalid data");
objInput.focus();
return false;
}
}
Assign the onpaste event handler just as you would any other event handler:
<input type="text" name="txtExample"
onkeypress="return maskKeyPress(event)"
onchange="maskChange(event)" onpaste="return
maskPaste(event)">
Other browsers ignore the onpaste handler. Example 7b uses the maskPaste() function recognized by IE. If you try to paste some letters into the textbox you'll see the invalid data alert and the browser won't paste the text. However, pasting numbers works without a problem. Finally, you can tackle NS6.
Earlier, you saw that you can detect the paste keystroke combination (Ctrl + V) in NS6, which means that you can block it. Unfortunately, NS6 doesn't give you the ability to see what value is going to be pasted, so there is no way to know whether to block the paste operation. In any case, there's no way to block the Paste command from the context menu. You could block the use of the context menu altogether, but that puts some real handcuffs on our users. I've never been comfortable with completely blocking the pasting ability. All this considered, the solution for NS4 is fine for NS6 as well.
|
|
 |
TALK
BACK |
|
Creating a masked edit text box in DTHML is not as straightforward as it seems at first. Do you know of other masked edit examples? Join the discussions at web.dhtml.scripting to get answers, make comments, or help others with their problems.
|
|
|
|
|
|
|