JS Bin demo
This regex transform each lower case word to upper case. I have a full name input field. I do want the user to see that each word's first letter he/she pressed is converted to uppercase in the input field.
I have no idea how to properly replace the selected characters in the current input field.
$('input').on('keypress', function(event) {
var $this = $(this),
val = $this.val(),
regex = /\b[a-z]/g;
val = val.toLowerCase().replace(regex, function(letter) {
return letter.toUpperCase();
});
// I want this value to be in the input field.
console.log(val);
});
Given i.e: const str = "hello world" to become Hello world
const firstUpper = str.substr(0, 1).toUpperCase() + str.substr(1);
or:
const firstUpper = str.charAt(0).toUpperCase() + str.substr(1);
or:
const firstUpper = str[0] + str.substr(1);
input {
text-transform: capitalize;
}
http://jsfiddle.net/yuMZq/1/
Using text-transform would be better.
You can convert the first letter to Uppercase and still avoid the annoying problem of the cursor jumping to the beginning of the line, by checking the caret position and resetting the caret position. I do this on a form by defining a few functions, one for all Uppercase, one for Proper Case, one for only Initial Uppercase... Then two functions for the Caret Position, one that gets and one that sets:
function ProperCase(el) {
pos = getInputSelection(el);
s = $(el).val();
s = s.toLowerCase().replace(/^(.)|\s(.)|'(.)/g,
function($1) { return $1.toUpperCase(); });
$(el).val(s);
setCaretPosition(el,pos.start);
}
function UpperCase(el) {
pos = getInputSelection(el);
s = $(el).val();
s = s.toUpperCase();
$(el).val(s);
setCaretPosition(el,pos.start);
}
function initialCap(el) {
pos = getInputSelection(el);
s = $(el).val();
s = s.substr(0, 1).toUpperCase() + s.substr(1);
$(el).val(s);
setCaretPosition(el,pos.start);
}
/* GETS CARET POSITION */
function getInputSelection(el) {
var start = 0, end = 0, normalizedValue, range,
textInputRange, len, endRange;
if (typeof el.selectionStart == 'number' && typeof el.selectionEnd == 'number') {
start = el.selectionStart;
end = el.selectionEnd;
} else {
range = document.selection.createRange();
if (range && range.parentElement() == el) {
len = el.value.length;
normalizedValue = el.value.replace(/\r\n/g, "\n");
// Create a working TextRange that lives only in the input
textInputRange = el.createTextRange();
textInputRange.moveToBookmark(range.getBookmark());
// Check if the start and end of the selection are at the very end
// of the input, since moveStart/moveEnd doesn't return what we want
// in those cases
endRange = el.createTextRange();
endRange.collapse(false);
if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
start = end = len;
} else {
start = -textInputRange.moveStart("character", -len);
start += normalizedValue.slice(0, start).split("\n").length - 1;
if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
end = len;
} else {
end = -textInputRange.moveEnd("character", -len);
end += normalizedValue.slice(0, end).split("\n").length - 1;
}
}
}
}
return {
start: start,
end: end
};
}
/* SETS CARET POSITION */
function setCaretPosition(el, caretPos) {
el.value = el.value;
// ^ this is used to not only get "focus", but
// to make sure we don't have it everything -selected-
// (it causes an issue in chrome, and having it doesn't hurt any other browser)
if (el !== null) {
if (el.createTextRange) {
var range = el.createTextRange();
range.move('character', caretPos);
range.select();
return true;
}
else {
// (el.selectionStart === 0 added for Firefox bug)
if (el.selectionStart || el.selectionStart === 0) {
el.focus();
el.setSelectionRange(caretPos, caretPos);
return true;
}
else { // fail city, fortunately this never happens (as far as I've tested) :)
el.focus();
return false;
}
}
}
}
Then on document ready I apply a keyup event listener to the fields I want to be checked, but I only listen for keys that can actually modify the content of the field (I skip "Shift" key for example...), and if user hits "Esc" I restore the original value of the field...
$('.updatablefield', $('#myform')).keyup(function(e) {
myfield=this.id;
myfieldname=this.name;
el = document.getElementById(myfield);
// or the jquery way:
// el = $(this)[0];
if (e.keyCode == 27) { // if esc character is pressed
$('#'+myfield).val(original_field_values[myfield]); // I stored the original value of the fields in an array...
// if you only need to do the initial letter uppercase, you can apply it here directly like this:
initialCap(el);
} // end if (e.keyCode == 27)
// if any other character is pressed that will modify the field (letters, numbers, symbols, space, backspace, del...)
else if (e.keyCode == 8||e.keycode == 32||e.keyCode > 45 && e.keyCode < 91||e.keyCode > 95 && e.keyCode < 112||e.keyCode > 185 && e.keyCode < 223||e.keyCode == 226) {
// if you only need to do the initial letter uppercase, you can apply it here directly like this:
initialCap(el);
} // end else = if any other character is pressed //
}); // end $(document).keyup(function(e)
You can see a working fiddle of this example here: http://jsfiddle.net/ZSDXA/
Simply put:
$this.val(val);
$(document).ready(function() {
$('input').on('keypress', function(event) {
var $this = $(this),
val = $this.val();
val = val.toLowerCase().replace(/\b[a-z]/g, function(letter) {
return letter.toUpperCase();
});
console.log(val);
$this.val(val);
});
});
As #roXon has shown though, this can be simplified:
$(document).ready(function() {
//alert('ready');
$('input').on('keypress', function(event) {
var $this = $(this),
val = $this.val();
val = val.substr(0, 1).toUpperCase() + val.substr(1).toLowerCase();
$this.val(val);
});
});
An alternative, and better solution in my opinion, would be to only style the element as being capitalized, and then do your logic server side.
This removes the overhead of any javascript, and ensures the logic is handled server side (which it should be anyway!)
$('input').on('keyup', function(event) {
$(this).val(function(i, v){
return v.replace(/[a-zA-Z]/, function(c){
return c.toUpperCase();
})
})
});
http://jsfiddle.net/AbxVx/
This will do for every textfield call function on keyup
where id is id of your textfield and value is value you type in textfield
function capitalizeFirstLetter(value,id)
{
if(value.length>0){
var str= value.replace(value.substr(0,1),value.substr(0,1).toUpperCase());
document.getElementById(id).value=str;
}
}
only use this This work for first name in capital char
style="text-transform:capitalize;
Like
<asp:TextBox ID="txtName" style="text-transform:capitalize;" runat="server" placeholder="Your Name" required=""></asp:TextBox>
$('.form-capitalize').keyup(function(event) {
var $this = $(this),
val = $this.val(),
regex = /\b[a-z]/g;
val = val.toLowerCase().replace(regex, function(letter) {
return letter.toUpperCase();
});
this.value = val;
// I want this value to be in the input field.
console.log(val);
});
Related
I'm working on a "autocomplete usernames when TAB is pressed" feature.
I've been able to detect # and to search in a username list.
How to perform the autocompletion now, with a different matching username each time we press TAB ?
var userlist = ['bonjour', 'bleuet', 'bonobo', 'coucou'];
function getCaretPosition(ctrl) {
var start, end;
if (ctrl.setSelectionRange) {
start = ctrl.selectionStart;
end = ctrl.selectionEnd;
} else if (document.selection && document.selection.createRange) {
var range = document.selection.createRange();
start = 0 - range.duplicate().moveStart('character', -100000);
end = start + range.text.length;
}
return {
start: start,
end: end
}
}
$('#writing').keydown(function(e) {
if (e.keyCode == 9) {
var caret = getCaretPosition(this);
var word = /\S+$/.exec(this.value.slice(0, this.value.indexOf(' ',caret.end)));
word = word ? word[0] : null;
if (word.charAt(0) === '#')
alert(userlist.filter((x) => x.indexOf(word.slice(1)) === 0));
e.preventDefault();
return false;
}
});
#writing { width: 500px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<textarea id="writing">Hello #b what's up? hello #you as well... Type #b and then "TAB" key it should autocomplete usernames
</textarea>
Here is the solution for your issue:
I used .on() to bind keydown to textbox, rather than keypress.
var userlist = ['bonjour', 'bleuet', 'bonobo', 'coucou'];
function getCaretPosition(ctrl) {
var start, end;
if (ctrl.setSelectionRange) {
start = ctrl.selectionStart;
end = ctrl.selectionEnd;
} else if (document.selection && document.selection.createRange) {
var range = document.selection.createRange();
start = 0 - range.duplicate().moveStart('character', -100000);
end = start + range.text.length;
}
return {
start: start,
end: end
}
}
$('#writing').keydown(function(e) {
if (e.keyCode == 9) {
var caret = getCaretPosition(this);
var word = /\S+$/.exec(this.value.slice(0, this.value.indexOf(' ',caret.end)));
word = word ? word[0] : null;
if (word.charAt(0) === '#')
//alert(userlist.filter((x) => x.indexOf(word.slice(1)) === 0));
var stringParts = $(this).val().split('#');
var nameToInsert = userlist.filter((x) => x.indexOf(word.slice(1)) === 0)[0];
var completeString = stringParts[0] + '#' + nameToInsert;
$(this).val(completeString);
e.preventDefault();
return false;
}
});
#writing { width: 500px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<textarea id="writing">Hello #b what's up? hello #you as well... Type #b and then "TAB" key it should autocomplete usernames
</textarea>
Now it completes the name. But I would work on improving on the algorithm predicting the name.
Here's a very basic example that works in modern browsers (Chrome, Firefox, Edge):
const users = ['asdasd', 'fgsfds', 'Foobar']
const input = document.getElementById('input')
const patt = /\S+$/
input.addEventListener('keydown', e => {
if (e.key !== 'Tab') {
return
}
e.preventDefault()
const start = input.selectionStart
const seg = input.value.slice(0, start)
const match = (seg.match(patt) || [])[0]
if (!match) {
return
}
const idx = users.findIndex(x => x.startsWith(match))
if (idx < 0) {
return
}
const replace = users[users[idx] === match ? (idx + 1) % users.length : idx]
const newSeg = seg.replace(patt, replace)
input.value = newSeg + input.value.slice(start)
input.setSelectionRange(newSeg.length, newSeg.length)
})
<input type="text" id="input" size="50" value="bla asd bla fgs">
It cycles through the names and works at any point in the line. Support for older browsers can be added with Babel and es6-shim.
Replace keypress with keydown. Keypress doesn't fire when tab is pressed, I guess because tab gets input out of focus.
EDIT:
Not perfect, gets undefined sometimes, but you can work from here
EDIT:
ok don't mind this, it's half done and #slikts solution is obviously better, made from scratch and all.
var userlist = ['bonjour', 'bleuet', 'bonobo', 'coucou'];
function getCaretPosition(ctrl) {
var start, end;
if (ctrl.setSelectionRange) {
start = ctrl.selectionStart;
end = ctrl.selectionEnd;
} else if (document.selection && document.selection.createRange) {
var range = document.selection.createRange();
start = 0 - range.duplicate().moveStart('character', -100000);
end = start + range.text.length;
}
return {
start: start,
end: end
}
}
function setCaretPosition(elem, caretPos, caretPosEnd) {
caretPosEnd = caretPosEnd || caretPos;
if(elem != null) {
if(elem.createTextRange) {
var range = elem.createTextRange();
range.move('character', caretPos);
range.select();
}
else {
if(elem.selectionStart) {
elem.focus();
elem.setSelectionRange(caretPos, caretPosEnd);
}
else
elem.focus();
}
}
}
function getIndexCloserTo(str, char, ref) {
if(str.indexOf(char) == -1) return false;
//flip string and find char beggining from reference point
var nstr = str.split("").reverse().join("");
return str.length - 1 - nstr.indexOf(char, str.length - 1 - ref);
}
var lastWordToMatch = "";
var lastAddedWord = "";
var lastIndexUsed = 0;
$(document).ready( function() {
$('#writing').keydown(function(e) {
if (e.keyCode == 9) {
var caret = getCaretPosition(this);
//Get username input part, from the "#" closer to the cursor
//to the position of the cursor
var beginning = getIndexCloserTo(this.value, '#', caret.start);
if( beginning !== false){
var word = this.value.slice( beginning , caret.start);
word = word ? word[0] : null;
if (word.charAt(0) === '#'){
//Get array of names that match what is written after the #
var usermatches = userlist.filter((x) => x.indexOf(word.slice(1)) === 0);
//Check if any matches were found
if( usermatches.length > 0 ){
//If the word is the same as last time, use the next match
if( word == lastWordToMatch ){
//use mod to circle back to beginning of array
index = (lastIndexUsed + 1 ) % usermatches.length;
lastIndexUsed = index;
} else {
//otherwise get first match
index = 0;
lastWordToMatch = word;
}
var text = this.value;
//Remove #
word = word.slice(1);
//replace the portion of the word written by the user plus the
//word added by autocompletion, with the match
$(this).val(text.replace(word+lastAddedWord, usermatches[index]) );
//save the replacement for the previous step, without the user input
//just what autocompetion added
lastAddedWord = usermatches[index].replace(word, '');
//put cursor back where it was
setCaretPosition(this,caret.start);
}
}
}
e.preventDefault();
return false;
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="writing">Hello #b what's up? hello #you as well... Type #b and then "TAB" key it should autocomplete usernames
</textarea>
Friends ,I have a text box for date to be inserted by the user but i want it to allow user to insert only "dd" ,"mm" and "yyyy" values ,slashes(/)should be already present and as soon as the user inserts "dd" values the pointer should move directly behind the slash for "mm" value and on pressing backspace it should delete the "mm" or "dd "values not the slashes(/).
Here is what i have tried but it does not give me the desired result-
function dateCheck(){
var d_value=$("#pdate").val();
if(d_value.length =="2" || d_value.length =="5")
{
$('#pdate').val($('#pdate').val()+"/");
}
}
html code-
Date:<input type="text" name="p_date" id="pdate" onkeydown="dateCheck()" placeholder="DD/MM/YYYY" required />
There's probably plugins out there, but nobody's been too forthcoming with any. Here's something I've knocked up during my lunch break :).
It's not perfect, and could be improved with some tweaking. For example, highlighting multiple characters for deletion is a bit screwy, but hopefully it's not a bad starter for 10. Credit to this post for getting/setting the caret position. Also, it does allow invalid dates right now - 12/34/5678. It wouldn't be too difficult to sort that out. I might stick something on Git and finish it off when I get home.
I've hard-coded it for dd/mm/yyyy format, but, again, with improvments, it could use the user locale.
$.fn.textboxDatePicker = function() {
var _getCaret = function(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;
};
var _setCaretPosition = function(elem, caretPos) {
if (caretPos == 2 || caretPos == 5) {
caretPos++;
}
if (elem != null) {
if (elem.createTextRange) {
var range = elem.createTextRange();
range.move('character', caretPos);
range.select();
} else {
if (elem.selectionStart) {
elem.focus();
elem.setSelectionRange(caretPos, caretPos);
}
else elem.focus();
}
}
};
$(this).val('dd/mm/yyyy');
$(this).on("keydown", function(e) {
var keyCode = e.which || e.charCode || e.keyCode;
var key = String.fromCharCode(keyCode);
// arrows, home, end
if ([35, 36].indexOf(keyCode) > -1) {
return true;
}
if (keyCode == 37) {
var newCaretPos = _getCaret(this) - 1;
if ([2, 5].indexOf(newCaretPos) > -1) {
_setCaretPosition(this, newCaretPos - 1);
return false;
}
return true;
}
if (keyCode == 39) {
var newCaretPos = _getCaret(this) + 1;
if ([2, 5].indexOf(newCaretPos) > -1) {
_setCaretPosition(this, newCaretPos + 1);
return false;
}
return true;
}
// backspace
if (keyCode == 8) {
var text = this.value;
var caret = _getCaret(this);
if (caret == 3 || caret == 6) {
caret = caret - 2;
} else {
caret--;
}
if (caret < 0) {
return false;
}
var output = text.substring(0, caret);
key = 'd';
if (caret > 2) {
key = 'm'
};
if (caret > 4) {
key = 'y'
};
this.value = output + key + text.substring(caret + 1);
_setCaretPosition(this, caret);
return false;
}
if (/[0-9]/.test(key)) {
var text = this.value;
var caret = _getCaret(this);
if (caret > 9) {
return false;
}
var output = text.substring(0, caret);
this.value = output + key + text.substring(caret + 1);
_setCaretPosition(this, caret + 1);
}
return false;
});
};
$('.date').textboxDatePicker();
UPDATE
Might be overthinking this. Could you just use 3 separate boxes and style them to look like one, with a little JS to sort out focusing between them?
https://jsfiddle.net/w9by2350/3/
MUCH cleaner!
Try it
function datecheck(){
value=$(#input_id).val();
if(value.match(/^\d\d?\/\d\d?\/\d\d\d\d$/){
return true;
}else{
alert("not valid format")
}
}
I am trying to make a typing game in javascript with jQuery but facing a issue.
How can I highlight the character the user types when they type it?
I have example in my div
<div id="theWord">tjurkey</div>
When the user starts typing "tj.." it should highlight t, then j, as they type it.
Currently I am stuck here:
$("body").keypress(function(e) {
if (e.which !== 0) {
var t = String.fromCharCode(e.which);
if ( t != undefined){ wordContainer += t.replace("undefined",""); }
if ( wordContainer == theWord){
alert("You typed the word" + theWord);
}
}
});
Ex. the word is "Tjurkey", if user start typing P it shouldn't highlight anything, because It's TJurkey and not P.
If user types "T" to start with it should highlight the "T" like Tjurkey, if user type "a" after that it shouldn't highlight it, because the word is Tjurkey and not Ta.... when the user then type j it should hightlight the j, because the word is TJ...urkey.. got the point?
Demo: http://jsfiddle.net/cVaHb/
var $target = $('#theWord'),
t = ''
$("body").keypress(function(e) {
if (e.which !== 0) {
t += String.fromCharCode(e.which);
var text = $target.text(),
pos = text.search(t);
if(pos > -1){
$target.html(
text.substring(0,pos)
+'<span class="highlight">'+t+'</span>'
+text.substring(pos+t.length)
);
}else{
$target.text(text);
}
}
});
CSS:
.highlight {
background: yellow;
}
Edit: If you want to ignore wrong letters, you can use
var $target = $('#theWord'),
t = ''
$("body").keypress(function(e) {
if (e.which !== 0) {
var newt = t + String.fromCharCode(e.which);
var text = $target.text(),
pos = text.search(newt);
if(pos > -1){
t = newt;
$target.html(text.substring(0,pos)+'<span class="highlight">'+t+'</span>'+text.substring(pos+t.length));
}
}
});
Demo: http://jsfiddle.net/cVaHb/1/
Here, to get you started
var t = "";
var word = $("#theWord").text();
$("body").keypress(function (e) {
if (e.which !== 0) {
t += String.fromCharCode(e.which);
if (word.substring(0, t.length) == t) {
$("#theWord").html("<span class='highlight'>" + t +"</span>"+ word.substring(t.length));
}
else
{
t=t.substring(0,t.length - 1);
}
}
});
check it out here:
http://jsfiddle.net/zahirdhada/UBbF7/1/
You can get the typed characters and find the starting and ending points of those in your string. Then you have to wrap that text with a span
ex: if user typed tj you should write a script to fill
<div id="theWord"><span style="color:red">tj</span>urkey</div>
in in Input field, if the user presses Backspace or Delete key, is there a way to get the deleted character.
I need to check it against a RegExp.
Assuming the input box has an id 'input'. Here is how with least amount of code you can find out the last character from the input box.
document.getElementById("input").onkeydown = function(evt) {
const t = evt.target;
if (evt.keyCode === 8) { // for backspace key
console.log(t.value[t.selectionStart - 1]);
} else if (evt.keyCode === 46) { // for delete key
console.log(t.value[t.selectionStart]);
}
};
<input id="input" />
The following will work in all major browsers for text <input> elements. It shouldn't be used for <textarea> elements because the getInputSelection function doesn't account for line breaks correctly in IE. See this answer for a (longer) function that will do this.
function getInputSelection(input) {
var start = 0, end = 0;
input.focus();
if ( typeof input.selectionStart == "number" &&
typeof input.selectionEnd == "number") {
start = input.selectionStart;
end = input.selectionEnd;
} else if (document.selection && document.selection.createRange) {
var range = document.selection.createRange();
if (range) {
var inputRange = input.createTextRange();
var workingRange = inputRange.duplicate();
var bookmark = range.getBookmark();
inputRange.moveToBookmark(bookmark);
workingRange.setEndPoint("EndToEnd", inputRange);
end = workingRange.text.length;
workingRange.setEndPoint("EndToStart", inputRange);
start = workingRange.text.length;
}
}
return {
start: start,
end: end,
length: end - start
};
}
document.getElementById("aTextBox").onkeydown = function(evt) {
evt = evt || window.event;
var keyCode = evt.keyCode;
var deleteKey = (keyCode == 46), backspaceKey = (keyCode == 8);
var sel, deletedText, val;
if (deleteKey || backspaceKey) {
val = this.value;
sel = getInputSelection(this);
if (sel.length) {
deletedText = val.slice(sel.start, sel.end);
} else {
deletedText = val.charAt(deleteKey ? sel.start : sel.start - 1);
}
alert("About to be deleted: " + deletedText);
}
};
No, there is no variable that stores the deleted char. Unless you have a history for Undo/Redo, but it would be difficult to get the information out of that component.
Easiest would be to compare the contents of the input field before and after delete/backspace have been pressed.
You could try something with the caret position:
function getCaretPosition(control){
var position = {};
if (control.selectionStart && control.selectionEnd){
position.start = control.selectionStart;
position.end = control.selectionEnd;
} else {
var range = document.selection.createRange();
position.start = (range.offsetLeft - 1) / 7;
position.end = position.start + (range.text.length);
}
position.length = position.end - position.start;
return position;
}
document.getElementById('test').onkeydown = function(e){
var selection = getCaretPosition(this);
var val = this.value;
if((e.keyCode==8 || e.keyCode==46) && selection.start!==selection.end){
alert(val.substr(selection.start, selection.length));
} else if(e.keyCode==8){
alert(val.substr(selection.start-1, 1));
} else if(e.keyCode==46){
alert(val.substr(selection.start, 1));
}
}
Tested on Chrome 6. See jsFiddle for an example
I have some html
<input type="text" name="name" value="" id="name">
<div id="preview"></div>
The rules for entry into the field:
Letters A-Z a-z 0-9 space and dash, no other characters allowed
Entry of forbidden characters should do nothing
The rules for the div:
Show each characters as it is entered into the input field
Do not show characters that are forbidden
When a space is encountered, show it as a dash
I have had various potions working, not working, or misbehaving. This version seems to work in all cases I can test other than backspace/delete is non functional. Only tested in Safari so far.
There are other "gotcha" areas, like entering in text in-between already entered text, select all, using the arrow keys, all these play a role in this problem.
$(document).ready(function(){
$('#name').keypress(function(e) {
// get key pressed
var c = String.fromCharCode(e.which);
// var d = e.keyCode? e.keyCode : e.charCode; // this seems to catch arrow and delete better than jQuery's way (e.which)
// match against allowed set and fail if no match
var allowed = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890- ';
if (e.which != 8 && allowed.indexOf(c) < 0) return false; // d !== 37 && d != 39 && d != 46 &&
// just replace spaces in the preview
window.setTimeout(function() {$('#preview').text($('#name').val().replace(/ /g, '-'));}, 1);
});
});
If there is a way to put a monetary bounty on this post, let me know. Yes, that is where I am at with this one :)
I tested the following in Firefox, Safari and Internet Explorer. Unless I didn't fully understand your objective, I believe this should solve your problem.
I ended up writing a jQuery plugin to handle the input caret position. The plugin source is included below, or available on the jQuery plugin site (http://plugins.jquery.com/project/caret-range).
$(document).ready(function () {
var InvalidPattern = /[^a-z0-9\- ]+/gi;
var SpacePattern = / /g;
var name = $("#name");
var preview = $("#preview");
var callback = function (e) {
setTimeout(function () {
// Get range and length to restore caret position
var range = name.caret();
var len = name.val().length;
// Blur element to minimize visibility of caret jumping
name.get(0).blur();
// Remove invalid characters, and update preview
name.val(name.val().replace(InvalidPattern, ""));
preview.text(name.val().replace(SpacePattern, "-"));
// Restore caret position
var diff = len - name.val().length;
name.caret(range.start - diff, range.end - diff);
}, 0);
};
name.keypress(callback);
name.keydown(callback); // Needed by IE to update preview for Delete and Backspace
});
/*
* jQuery Caret Range plugin
* Copyright (c) 2009 Matt Zabriskie
* Released under the MIT and GPL licenses.
*/
(function($) {
$.extend($.fn, {
caret: function (start, end) {
var elem = this[0];
if (elem) {
// get caret range
if (typeof start == "undefined") {
if (elem.selectionStart) {
start = elem.selectionStart;
end = elem.selectionEnd;
}
else if (document.selection) {
var val = this.val();
var range = document.selection.createRange().duplicate();
range.moveEnd("character", val.length)
start = (range.text == "" ? val.length : val.lastIndexOf(range.text));
range = document.selection.createRange().duplicate();
range.moveStart("character", -val.length);
end = range.text.length;
}
}
// set caret range
else {
var val = this.val();
if (typeof start != "number") start = -1;
if (typeof end != "number") end = -1;
if (start < 0) start = 0;
if (end > val.length) end = val.length;
if (end < start) end = start;
if (start > end) start = end;
elem.focus();
if (elem.selectionStart) {
elem.selectionStart = start;
elem.selectionEnd = end;
}
else if (document.selection) {
var range = elem.createTextRange();
range.collapse(true);
range.moveStart("character", start);
range.moveEnd("character", end - start);
range.select();
}
}
return {start:start, end:end};
}
}
});
})(jQuery);
After tinkering around I have refactored my previous solution. This version should behave identical to Twitter. I am keeping my old answer alive simply b/c it is technically valid, and this allows comparing the different approaches.
$(document).ready(function () {
var SpacePattern = / /g;
var name = $("#name");
var preview = $("#preview");
var updatePreview = function () {
preview.text(name.val().replace(SpacePattern, "-"));
};
name.keypress(function (e) {
if (e.which > 0 && // check that key code exists
e.which != 8 && // allow backspace
e.which != 32 && e.which != 45 && // allow space and dash
!(e.which >= 48 && e.which <= 57) && // allow 0-9
!(e.which >= 65 && e.which <= 90) && // allow A-Z
!(e.which >= 97 && e.which <= 122) // allow a-z
) {
e.preventDefault();
}
else {
setTimeout(updatePreview, 0);
}
});
name.keyup(updatePreview); // Needed by IE for Delete and Backspace keys
});
Try this:
1. When key down, copy the previous TextField value.
2. When key up, use RegEx to validate the text (something like /^[a-zA-Z0-9 -]*$/), if unmatch, replace the value with the old one.
Here is the code:
var ValidPattern = /^[a-zA-Z0-9\- ]*$/;
$(document).ready(function(){
$('#name').keydown(function(e) {
var aValue = $('#name').val();
$('#name').attr("oldValue", aValue);
return true;
});
$('#name').keyup(function(e) {
var aValue = $('#name').val();
var aIsMatch = aValue.search(ValidPattern) != -1;
if(aIsMatch) {
$('#preview').text(aValue);
} else {
var aOldValue = $('#name').attr("oldValue");
$('#name') .val (aOldValue);
$('#preview').text(aOldValue);
}
});
});
Try it.
I think the best method will be to keep a button and after entering the text inside the text box and clicking on the button show it in the div. It will be much more easier and user friendly.
It would be better not to try hindering the default actions of a user with the keyboard.