Given a keydown event in the browser, how can I predict whether that key event will result in character input? For example, hitting the left arrow doesn't input characters but hitting the a key inputs an A (unless ctrl or alt is down).
I don't need to know what character will be input, just whether the key event will result in an input.
I'm targeting Chrome. Bonus points if your solution works in an IME.
Note: I'm asking about the keydown event, not a downstream event like keypress or oninput.
There's an HTML 5 event: input. MDN: https://developer.mozilla.org/en-US/docs/Web/Reference/Events/input. Other than that there's no proper solution.
Ok, I think I have a solution. I don't know how good it is but it works. Have a look: http://jsfiddle.net/tLPsL/
It's basically saving the value of the input onkeydown and checking it in onkeyup.
$('#sattar').keydown(function() {
window.SATTAR = $(this).val();
});
$('#sattar').keyup(function() {
if(window.SATTAR !== $(this).val()) {
alert("changed");
}
});
[updated]
use this
$(document).keydown(function(event){
console.log(event.which);
});
and filter the value of the event.which according to your needs using the ascii values and exclude the numbers that appear with unwanted buttons
for example (this example demonstrates accepting small letters only):
$(document).keydown(function(event){
var x = event.which;
if (x <= 90 && x >=65) console.log('accepted');
else console.log('not accepted');
});
JSFiddle
[update] :
If you don't like this method you can use another that detects an input to any textfield or textarea :
$('input,textarea').change(function(){
console.log('input detected!');
});
$(document).keyup(function(event){
var x = $(event.target);
if (x[0].nodeName == 'INPUT' || x[0].nodeName == 'TEXTAREA'){ //you can filter the backspace if you don't want to consider it a change on the input by anding it with the whole argument here using the key number explained above
x.blur().focus();
}
});
DEMO
note: The first method works for all languages as the same keyboard keys are used for inputs of different characters but they still can type.
Sources && tips:
I saw the characters keydata list in this site.
-To make it crossplatform and crossbrowser, I suggest you to watch this site
-You can test the keydown event here.
-Jquery also suggest to use key which because it normalizes keycode and charcode (i think this can be usefull for the crossbrowser part but I didn't find a table like the one I posted before for keycode), see details here.
To the end, a personal thought: I wouldn't appear rude by telling this so please, try to understand, you had 3 clear and working answer, should be your interest to improve details to make it working as you need, especially because, for many reason, (like time, hardware disponibility, no one pay us, freelancer site is elsewhere, etc etc), who are helping you, maybe, can't do your entirely work.
EDIT
Considering your needs, I wrote this code, keeps in mind that combination key are hard to handle, so, you should test this example before to re-use it. fiddle
<!DOCTYPE html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script>
$(document).keydown(
function(event){
if(event.target!='[object HTMLBodyElement]'){//Are we in an input?
if(!event.ctrlKey && !event.altKey){//Are we using a combo ctrl or alt?
if(event.keyCode==13 || event.keyCode==8 || event.keyCode==32 || (event.keyCode>45 && event.keyCode<91) || event.keyCode==188 || (event.keyCode>189 && event.keyCode<193) || (event.keyCode>218 && event.keyCode<222)){
//It is a char?
document.getElementById('valid').innerHTML+=event.keyCode+' ';
document.getElementById('idlast').innerHTML=event.target.id;
}
}
}
}
);
</script>
</head>
<body>
<input id="a" type="text"></input>
<textarea id="b">a</textarea>
<div id="c" contenteditable="true">a</div>
<div id="d" style="width:200px;height:200px;background-color:red">a</div>
last keydown in: <span id="idlast"></span><br>
for keypress in input:<span id="valid"></span><br>
</body>
</html>
END EDIT
For first if the focus is on an object that is not an input(textarea,contenteditable...) you are targeting the body. So if the target is the body, for sure you are not writing somewhere.
Then I suggest you to see this example, keypress is probably usefull for your aim, because it seems to don't register keys that aren't an input.
<!DOCTYPE html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script>
$(document).keypress(
function(event){
if(event.target!='[object HTMLBodyElement]'){
document.getElementById('valid').innerHTML=document.getElementById('valid').innerHTML+event.keyCode+' ';
document.getElementById('idlast').innerHTML=event.target.id;
}else{
document.getElementById('out').innerHTML=document.getElementById('out').innerHTML+event.keyCode+' ';
}
}
);
$(document).keydown(function(e){document.getElementById('down').innerHTML=document.getElementById('down').innerHTML+e.keyCode+' ';});
</script>
</head>
<body>
<input id="a" type="text"></input>
<textarea id="b">a</textarea>
<div id="c" contenteditable="true">a</div>
<div id="d" style="width:200px;height:200px;background-color:red">a</div>
last keypress input id: <span id="idlast"></span><br>
for keypress in input:<span id="valid"></span><br>
for keypress out:<span id="out"></span><br>
for keydown:<span id="down"></span><br>
</body>
</html>
Related
Sorry, I am not a very best Javascript-programmer, but I am making a homepage for my website ( http://coins.kalf999.com/menu.php) and I was producing some code, but I was suprised it did not work untill....now!
But I still not understand why....
Who can help me..?
I made some small code to show the difference.
In the 1st textarea I can copy some text, press CTRL-C, which hides the textarea and you can test the contents of the clipboard in the 2nd textarea. I use a 1 millescond setTimeout-function, which works !
My old code was the second example:
In the 3rd textarea I can copy some text again, press CTRL-C, which hides the textarea and test the contents of the clipboard in the 4rd textarea.
I not use setTimeout-function, which , obviously, not works !
I can not imagine that a "hidden" object is creating a malfunction for a Copy-command.....
What happens over here...? ;(
I made test-program called tst.html and tst.js
<html>
<head>
<script type="text/javascript" src="tst.js"></script>
</head>
<body>
<div id = "box1"></div>
<div id = "testarea1"></div>
<div id = "box2"></div>
<div id = "testarea2"></div>
<script>
document.getElementById("box1").innerHTML= '<textarea rows="4" onkeypress="CTRLC1(event)">Select some text and copy with CTRL-C.The <textarea> becomes hidden.</textarea>';
document.getElementById("testarea1").innerHTML= '<textarea rows="4" ">Paste text with CTRL-V</textarea>';
document.getElementById("box2").innerHTML= '<textarea rows="4" onkeypress="CTRLC2(event)">Select some text and copy with CTRL-C.The <textarea> becomes hidden.</textarea>';
document.getElementById("testarea2").innerHTML= '<textarea rows="4" ">Paste text with CTRL-V</textarea>';
</script>
</body>
</html>
and the JS-file test.js
function CTRLC1(event) {
if (event.ctrlKey == true){
var x = event.which || event.keyCode;
if (x==99 || x==67){
setTimeout(function(){document.getElementById("box1").style.visibility ="hidden";}, 1);
}
}
}
function CTRLC2(event) {
if (event.ctrlKey == true){
var x = event.which || event.keyCode;
if (x==99 || x==67){
document.getElementById("box2").style.visibility ="hidden";
}
}
}
You should be using onkeydown instead of onkeypress.
In theory, the keydown and keyup events represent keys being pressed or released, while the keypress event represents a character being typed. The implementation of the theory is not same in all browsers. More info: onKeyPress Vs. onKeyUp and onKeyDown
Here is the fiddle: http://jsfiddle.net/lucianmoldovan/g5c0pgwj/3/
Notice that on the second box, though the box gets hidden the text doesn't get copied. I imagine that the element is being hidden before the text gets copied to clipboard. Adding that setTimeout fixes this, even if you set it at 0 milliseconds.
Is there a way in javascript to detect if a word/string was typed in a textarea? I want to detect the string <svg> being inputed in Ace editor or CodeMirror and then do something else. Sounds like it has been implemented but I don't know how.
It is possible in Javascript to bind to the key up/down/press/etc events on DOM objects. You have to set the appropriate attribute in the HTML.
<textarea onkeyup='checkText(this.value);'></textarea>
This is the key line that calls the Javascript function with the value (text) of the textarea.
Here is a complete example that demonstrates this use. Listening on Key Up is preferred since the new character will be in the text value before the function is called.
<html>
<head>
<script type='text/javascript' >
var oldText = '';
function checkText(text)
{
if(text.length >= 1)
{
if(text == '<svg>' && text != oldText)
{
alert("<svg> found");
}
}
oldText = text;
}
</script>
<body>
<textarea onkeyup='checkText(this.value);'></textarea>
</body>
</html>
I know this is somewhat similar to the others' answers, but it offers an alternative approach:
document.getElementById('textArea').onkeypress = function() {
if(/\<svg\>/i.test(document.getElementById('textArea').value) === true) {
// do whatever you want here
}
}
If you're not familiar with RegExes in JS, they're a great way to find certain strings in things - say, a user's input, like you want. The i flag after the creation ignores the case, just in case you didn't know. Also, putting this script in the head without an onload event or something of the sort won't work - there's nothing for the script to search, since the document hasn't been fully loaded yet.
Hope this helped!
You can compare what is typed with what you expect using the onchange event.
<html>
<script>
function checktext(){
var val = document.getElementById("textbox").value;
// val is what is in the textbox
// compare val here
// for example
if (val == "<svg>"){
alert(val);
}
}
</script>
<body>
<textarea id="textbox" onchange="checktext()"></textarea>
</body>
</html>
In CodeMirror, the "change" event is fired whenever the code changes. You can simply scan the content for the string you are interested in when this fires. Or, if you expect a huge document, and want this to be efficient, you can only scan the changed part of the document (taking care to handle the case where the string is on the boundary of the changed and unchanged parts).
cmInstance.on("change", function(cm) {
if (cm.getValue().indexOf("<svg>") > -1)
doSomething();
});
Have following listener for keyboard ArrowDown event(it's key code is 40):
window.onload = function() {
var itemsContainer = document.getElementById('cities-drop');
document.addEventListener('keyup',function(event){
if (event.keyCode == 40 && itemsContainer.style.display=='block') {
event.preventDefault();
for (var i=0;i<itemsContainer.children.length-1;i++){
if (itemsContainer.getAttribute('class').substr('hovered')!=-1){
itemsContainer.children[i].setAttribute('class','');
itemsContainer.children[i].nextSibling.setAttribute('class','hovered');
//break;
}
}
}
});
in this case hovering jumps to last element in list, after ArrowDown pressed.
In case break is uncommented,it jumps to the second element and doesn't jumping any more.
Can't get the principle,how to do, that listener always listens...
EDIT
live demo
perhaps,it's a matter of closure,but i'm not certain
After looking at your code and realizing what you're trying to do, I think your error is using substr where you should be using indexOf. Here is the updated line:
if (itemsContainer.getAttribute('class').indexOf('hovered') != -1)
More detail:
What you were actually doing was using a substr with a string value for the start index. Not sure what the result of that would be, but apparently it's not -1, since the conditional was returning true every time, causing the next element to be hovered EVERY time, all the way down to the bottom of the list. With the break statement in there, it was executing the if-statement at the first element (causing the second element to be 'hovered'), and then quitting.
I would leave the break statement in there after correcting your code, so that the loop stops after it finds its match, and doesn't loop through the rest of the items unnecessarily.
EDIT:
I found a couple other issues in your code as well. Here is an example that works for me in IE and FF, at least (haven't tested in Safari, Opera or Chrome):
<html>
<head>
<style type="text/css">
.hovered
{
color:red;
}
</style>
<script type="text/JavaScript">
function move(event)
{
var itemsContainer = document.getElementById('cities-drop');
if (event.keyCode == 40 && itemsContainer.style.display == 'block')
{
if (event.preventDefault)
event.preventDefault();
if (event.cancelBubble)
event.cancelBubble();
if (event.stopImmediatePropagation)
event.stopImmediatePropagation();
for (var i=0; i<itemsContainer.children.length-1; i++)
{
if (itemsContainer.children[i].className.indexOf('hovered') != -1)
{
itemsContainer.children[i].className = "";
itemsContainer.children[i+1].className = "hovered";
break;
}
}
}
};
</script>
</head>
<body onkeydown="move(event)">
<div id="cities-drop" style="display:block;">
<p class="hovered">Item 1</p>
<p>Item 2</p>
<p>Item 3</p>
<p>Item 4</p>
<p>Item 5</p>
<p>Item 6</p>
<p>Item 7</p>
</div>
</body>
</html>
Detail: For me, in IE9, the function was never being called. Instead, I just made it a regular function and added an onkeydown event to the body tag.
Next, for cross-browser compatibility, you should check to make sure that event.preventDefault exists before using it. I was getting a JS error in IE.
In your if-statement, you had itemsContainer.getAttribute('class'). Firstly, you needed to use itemsContainer.children[i]. Secondly, .getAttribute('class') didn't work for me in IE, so I switched it to just .className.
Lastly, itemsContainer.children[i].nextSibling didn't work for me, but it's simple enough to just change it to itemsContainer.children[i+1] to get the next sibling.
You can try a simpler approach instead of using a loop:
window.onload = function() {
var itemsContainer = document.getElementById('cities-drop');
document.addEventListener('keyup',function(event) {
if (event.keyCode == 40 && itemsContainer.style.display=='block') {
event.preventDefault();
var previousHoveredChoice = itemsContainer.querySelector('.hovered');
previousHoveredChoice.className = '';
var currentHoveredChoice = previousHoveredChoice.nextSibling;
if (currentHoveredChoice) {
currentHoveredChoice.className = 'hovered';
}
}
});
//following code is copy-pasted from the live example
//just to close the onload function handler in this solution
document.addEventListener('keyup',function(event){
if (event.keyCode == 27) {
if (document.getElementById('cities-drop').style.display=='block'){
document.getElementById('cities-drop').style.display='none';
}
}
});
//end of copy-pasted code
};
There are a few things I can see that might be a problem. First of all, you update
itemsContainer.children[i].nextSibling which is itemsContainer.children[i+1]. That's why always the last element it selected if you skip the break. itemsComtainer[i+1] will always be hovered if there is on item matching the class.
Second problem is what Travesty3 is pointing out in his answer.
I also changed the if condition to check if the hovered class is on one of the children and not the container itself.
if (itemsContainer.children[i].getAttribute('class').match('hovered'))
I've modified the event handler with the following lines of code, and this seems to work fine:
document.addEventListener('keyup',function(event){
if (event.keyCode === 40 && itemsContainer.style.display==='block') {
event.preventDefault();
for (var i=0,l=itemsContainer.children.length;i<l;++i){
if (itemsContainer.children[i].getAttribute('class').match('hovered')){
itemsContainer.children[i].setAttribute('class','');
itemsContainer.children[i+1].setAttribute('class','hovered');
break;
}
}
}
});
Keep in mind that making such a drop down control is quite a lot of work. The user expects to navigate it using the keyboard. To make a great user experience, you should handle a number of keys, such as the arrow keys, tab to focus the control, space to open and close it, alpha-numeric input to focus on first matched element, etc.
If user experience is important, I'd recommend using a framework and a plugin for this. I personally prefer jquery and jquery ui, and there are a number of plugins for select drop downs. Another advantage is that if javascript is disabled by the client, or your javascript would err for some reason, most plugins fall back to a regular native select element, which would still work fine functionally.
I have used this plugin for a selectbox myself for a simple drop down:
http://www.abeautifulsite.net/blog/2011/01/jquery-selectbox-plugin/
Edit: I'm revoking this recommendation, as it doesn't work if multiple elements have the same name. If this is important, you should check out the Filament Group's selectmenu plugin instead:
http://filamentgroup.com/lab/jquery_ui_selectmenu_an_aria_accessible_plugin_for_styling_a_html_select/
//Edit
...and the jquery autocomplete plugin for a combobox also supporting written input:
http://jqueryui.com/demos/autocomplete/
I need to detect whether the user has pressed the dot key in the numeric keypad. I've written this first draft that works for me:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head><title></title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript"><!--
(function($){
var knownCodes = [
[110, 46], // Firefox, IE, Chrome
[78, 46] // Opera
];
var pressedCodes = [null, null];
$.fn.comma = function(){
this.live("keydown", function(e){
pressedCodes = [e.which, null];
}).live("keypress", function(e){
pressedCodes[1] = e.which;
for(var i=0, len=knownCodes.length; i<len; i++){
if(pressedCodes[0]==knownCodes[i][0] && pressedCodes[1]==knownCodes[i][1]){
$("#log").append("<li>Decimal key detected</li>");
break;
}
}
});
return this;
};
$(function(){
$('<ol id="log"></ol>').appendTo("body");
});
})(jQuery);
jQuery(function($){
$(".comma input:text, .comma textarea").css("border", "1px solid black").comma();
});
//--></script>
</head>
<body>
<form action="" method="get" class="comma" size="20">
<p><input type="text"></p>
<p><textarea rows="3" cols="30"></textarea></p>
</form>
</body>
</html>
However, I can only test it in a Windows XP box with a Spanish keyboard. My questions are:
Is it safe to read from e.which? I'm using it because both e.keyCode and e.charCode return undefined in at least one browser.
Does the operating system affect these numeric codes in some manner or it's only a browser stuff?
Do these codes depend on the keyboard layout?
Background info: I couldn't find a jQuery plugin to remap numeric keypad so I'm writing my own.
Update
I'll explain my exact need. Spanish keyboards that have a numeric keypad feature a . key. However, the decimal separator in Spanish is ,. That makes it annoying to type numbers in web applications. Some desktop apps like MS Excel remap this key so it inserts a comma. I'm trying to mimic that.
I've adapted a little script I've been using to post it here. That's how I got the values for the knownCodes arrays:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head><title></title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript"><!--
(function($){
$.fn.showKeyCodes = function(){
var log = function(e){
$("<li></li>").text(e.type + "(): [keyCode, charCode, which]=[" + e.keyCode + ", " + e.charCode + ", " + e.which + "]").appendTo("#log");
}
this.live("keydown", function(e){
log(e);
}).live("keypress", function(e){
log(e);
}).live("keyup", function(e){
log(e);
});
return this;
};
$(function(){
$('<ol id="log"></ol>').appendTo("body");
});
})(jQuery);
jQuery(function($){
$(".showKeyCodes input:text, .showKeyCodes textarea").css("border", "1px solid black").showKeyCodes();
});
//--></script>
</head>
<body>
<form action="" method="get" class="showKeyCodes" size="20">
<p><input type="text"></p>
<p><textarea rows="3" cols="30"></textarea></p>
</form>
</body>
</html>
Type the . key in your numeric keypad (or whatever key replaces it in your keyboard layout) and the key that corresponds to the same character in the alphabetical keypad. The goal is to detect you clicked the first one and not the second one.
Is it safe to read from e.which?
Normally in IE no, you only get keyCode (though on keypress it's actually a character code not a key code). Your code can read which because behind the scenes jQuery copies the keyCode value into which on IE. Without jQuery, you need property-sniffing code to know which one to pick. (You can't always read keyCode on keypress because it's not guaranteed to be provided and it's 0 on Firefox.)
Please note I don't want to detect a character: I want to detect a key.
You can't do that in keypress, which only gives you a character code (46, ASCII for .). You would instead have to trap keydown, which gives you access to a real key code (in the keyCode property, and also in browsers that aren't IE, in which).
The keyCode reported for the numeric keypad ./, button is 110 (ASCII for lower-case N). Except on opera where it's 78, ASCII for upper-case N and thus indistinguishable from pressing the N button.
So you could claim the keydown event and store a flag when key 110 or 78 was being depressed, then claim keypress. If the flag from the last keydown was set and the which (charCode) property is 46, return false to prevent the keypress going through, and then insert a , at the focus point instead. (This isn't quite reliable if there are multiple keys being pressed at once and autorepeat going on, though.)
Note that inserting a character at focus is itself non-trivial; see many previous questions here. You'll need branching code for IE (document.selection.createRange().text=...) and other modern browsers (changing the input's value based on selectionStart/selectionEnd). Older and mobile or niche browsers may not support either method of editing, so detect the lack of these properties and leave the keyboard alone if you can't do it.
Does the operating system affect these numeric codes in some manner or it's only a browser stuff?
Do these codes depend on the keyboard layout?
In general yes, though not in a way that will affect you here. Key events are in general still hugely variable cross-browser, cross-keyboard and cross-platform; they are best avoided if you can.
Personally I think the proper solution to a bad keyboard layout choice like Spanish's numpad decimal point would be to modify the layout using MSKLC.
Your code doesn't do anything on my end, so I'd say it probably does depend on keyboard layout. A quick check confirms that the output on my finnish qwerty keyboard is keycode 44, instead of the expected 46.
Some time after asking this question, I finally found a jQuery plugin that does exactly this: numpad-decimal-separator
This is a followup question to this question:
select all contents of textbox when it receives focus (Javascript or jQuery)
Basically I am using a textbox in conjunction with the jQuery masked input plugin(Edit: Link may no longer point at relevant version)
When the masked input textbox receives focus I want to select all of the contents of that textbox, but it seems as though having this plugin binded to the textbox prevents that. I was just wondering if there was a way around this.
Below is a sample .html page that demonstrates the issue:
<html>
<head>
<title></title>
</head>
<body>
<input id="masktest" type="text" value="01/01/2009" />
<br />
<input id="focustest" type="text" value="on focus will select all contents..." />
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript" src="http://jquery-joshbush.googlecode.com/files/jquery.maskedinput-1.2.1.pack.js"></script>
<script type="text/javascript">
$(function() {
$("#masktest").mask("99/99/9999");
// Contents of textboxes will be selected when receiving focus.
$("input[type=text]")
.focus(function() {
$(this).select();
});
});
</script>
</body>
</html>
I'm the author of the Masked Input Plugin for jQuery. I decided that this should be the default behavior for completed masks and I got it into the latest release. You can read the details here
Hey Jon, not too sure about the performance of this, but this should work:
$(function() {
// Contents of textboxes will be selected when receiving focus.
$("input[type=text]")
.focus(function() {
var mask = "99/99/9999";
$(this).unmask(mask).select().mask(mask);
});
});
its working for me in FF3.
$("input[type=text]").focus(function(e) {
var that = this;
setTimeout(function(){$(that).select();},10);
return false;
});
setTimeout will "queue" the select() execution, I was wondering about:
- Ok mask functions do your work THEN I'll select the content. That THEN is where the queue is useful.
Just an idea. I hope it works as expected.
Problem
Defaut value is deleting when focus
Resolve : added little patch code to mask.js file (jquery.maskedinput-1.2.2.min.js)
(function(a){var c=(a.browser.msie?"paste":"input")+".mask";var b=(window.orientation!=undefined);a.mask={definitions:{"9":"[0-9]",a:"[A-Za-z]","*":"[A-Za-z0-9]"}};a.fn.extend({caret:function(e,f){if(this.length==0){return}if(typeof e=="number"){f=(typeof f=="number")?f:e;return this.each(function(){if(this.setSelectionRange){this.focus();this.setSelectionRange(e,f)}else{if(this.createTextRange){var g=this.createTextRange();g.collapse(true);g.moveEnd("character",f);g.moveStart("character",e);g.select()}}})}else{if(this[0].setSelectionRange){e=this[0].selectionStart;f=this[0].selectionEnd}else{if(document.selection&&document.selection.createRange){var d=document.selection.createRange();e=0-d.duplicate().moveStart("character",-100000);f=e+d.text.length}}return{begin:e,end:f}}},unmask:function(){return this.trigger("unmask")},mask:function(j,d){if(!j&&this.length>0){var f=a(this[0]);var g=f.data("tests");return a.map(f.data("buffer"),function(l,m){return g[m]?l:null}).join("")}d=a.extend({placeholder:"_",completed:null},d);var k=a.mask.definitions;var g=[];var e=j.length;var i=null;var h=j.length;a.each(j.split(""),function(m,l){if(l=="?"){h--;e=m}else{if(k[l]){g.push(new RegExp(k[l]));if(i==null){i=g.length-1}}else{g.push(null)}}});return this.each(function(){var ORJ=$(this).val();var r=a(this);var m=a.map(j.split(""),function(x,y){if(x!="?"){return k[x]?d.placeholder:x}});var n=false;var q=r.val();r.data("buffer",m).data("tests",g);function v(x){while(++x<=h&&!g[x]){}return x}function t(x){while(!g[x]&&--x>=0){}for(var y=x;y<h;y++){if(g[y]){m[y]=d.placeholder;var z=v(y);if(z<h&&g[y].test(m[z])){m[y]=m[z]}else{break}}}s();r.caret(Math.max(i,x))}function u(y){for(var A=y,z=d.placeholder;A<h;A++){if(g[A]){var B=v(A);var x=m[A];m[A]=z;if(B<h&&g[B].test(x)){z=x}else{break}}}}function l(y){var x=a(this).caret();var z=y.keyCode;n=(z<16||(z>16&&z<32)||(z>32&&z<41));if((x.begin-x.end)!=0&&(!n||z==8||z==46)){w(x.begin,x.end)}if(z==8||z==46||(b&&z==127)){t(x.begin+(z==46?0:-1));return false}else{if(z==27){r.val(q);r.caret(0,p());return false}}}function o(B){if(n){n=false;return(B.keyCode==8)?false:null}B=B||window.event;var C=B.charCode||B.keyCode||B.which;var z=a(this).caret();if(B.ctrlKey||B.altKey||B.metaKey){return true}else{if((C>=32&&C<=125)||C>186){var x=v(z.begin-1);if(x<h){var A=String.fromCharCode(C);if(g[x].test(A)){u(x);m[x]=A;s();var y=v(x);a(this).caret(y);if(d.completed&&y==h){d.completed.call(r)}}}}}return false}function w(x,y){for(var z=x;z<y&&z<h;z++){if(g[z]){m[z]=d.placeholder}}}function s(){return r.val(m.join("")).val()}function p(y){var z=r.val();var C=-1;for(var B=0,x=0;B<h;B++){if(g[B]){m[B]=d.placeholder;while(x++<z.length){var A=z.charAt(x-1);if(g[B].test(A)){m[B]=A;C=B;break}}if(x>z.length){break}}else{if(m[B]==z[x]&&B!=e){x++;C=B}}}if(!y&&C+1<e){r.val(ORJ);w(ORJ.length,h)}else{if(y||C+1>=e){s();if(!y){r.val(r.val().substring(0,C+1))}}}return(e?B:i)}if(!r.attr("readonly")){r.one("unmask",function(){r.unbind(".mask").removeData("buffer").removeData("tests")}).bind("focus.mask",function(){q=r.val();var x=p();s();setTimeout(function(){if(x==j.length){r.caret(0,x)}else{r.caret(x)}},0)}).bind("blur.mask",function(){p();if(r.val()!=q){r.change()}}).bind("keydown.mask",l).bind("keypress.mask",o).bind(c,function(){setTimeout(function(){r.caret(p(true))},0)})}p()})}})})(jQuery);
if your 'completed' function doesn't work, try to replace this line:
if (settings.completed && next == len)
(this is line number 169 of noncompressed plugin) with that:
if (settings.completed && eval(+next - 1) == len)
While using this plugin with firebug, i've noticed, that 'next' variable jumps up over a symbol when last char of mask entered.
This way should work.
I found a better solution than timeout.
You can view jquery.maskedinput.js:293 there is a function for input focus and it is triggered only on inputs without "readonly" attribute so:
$("input[type=text]").attr("readonly", true).select().removeAttr("readonly");
...just like that. Works like a charm ;)