I have an app that must run in IE 7/8(compat). (I know, right?)
The app includes the following functionality....
If I click on a dropdown list, the list checks some values elsewhere and, depending on the number of matches it finds it enables or disables some of the options. I make this happen using the focus event of the dropdown list.
If I run this code in a real browser, it works fine. If I run it in IE7 or 8 with compatibility mode enabled, I have to click the DDL twice; the first time fires my focus event code and the 2nd to get it to drop down.
The markup:
<!DOCTYPE html>
<html>
<head>
<script data-require="jquery#*" data-semver="2.1.1" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<select id="aa">
<option>A</option>
<option>B</option>
<option>C</option>
<option>D</option>
<option>E</option>
<option>F</option>
<option>G</option>
</select>
<script src="script.js"></script>
</body>
</html>
The JS:
$("#aa").focus(function() {
var countSelectedEvents = 2;
var kids = $("#aa").children("option");
kids.removeAttr("disabled");
kids.removeAttr("title");
if (countSelectedEvents == 0) {
kids.slice(1).attr("disabled", "disabled");
kids.slice(1).attr("title", "This option is only available if one or more Events are selected");
kids.slice(4).attr("title", "This option is only available if exactly ONE Event is selected");
} else if (countSelectedEvents > 1) {
kids.slice(4).attr("disabled", "disabled");
kids.slice(4).attr("title", "This option is only available if exactly ONE Event is selected");
}
return true;
});
For convenience, you can find this code on plnkr. If anyone knows how I can get the DDL to drop open on the first click, I'd love to hear about it.
UPDATE:
This question here on Stack Overflow suggests triggering the focusout event, but that doesn't work either.
UPDATE II
It seems that this is a more generic IE error. It doesn't work in native mod in IE11 either! :-(
You have an extra opening bracket { in your .focus() function event. That's probably breaking your code.
Instead of .focus(function(){{}) , should be .focus(function(){})
(in other words, remove line 2 in your JS example and should be set)
Related
I want to generate a virtual keyboardEvent(tab). I did some research on the same and got few usefully answers, however it not working for me. I understand that Javascript is event driven programming language so User should press require key, but I also want to understand that can we generate an keyboard event through JavaScript.
function fnGenerateTabKeyEvent() {
var e = document.createEventObject("KeyboardEvent");
e.keyCode = 9; // tab's ASCII
document.getElementsByName("someTxtBox").fireEvent("onkeyup", e);
}
<input type="text" id="someTxtBox"/>
It's not working in IE8 and I'm not getting any error either. I just want that whenever I can this function it should an keyboardevent(tab) from that text box.
Source1,Source2. Any suggestion will be helpful.
I think you were too hasty, as your code works on my machine:
<html>
<body>
<input type="text" id="someTxtBox" onkeyup="window.alert(event.keyCode)"/>
<script type='text/javascript'>
function fnGenerateTabKeyEvent() {
var e = document.createEventObject("KeyboardEvent");
e.keyCode = 9; // tab's ASCII
document.getElementById("someTxtBox").fireEvent("onkeyup", e);
}
fnGenerateTabKeyEvent();
</script>
</body>
</html>
There're of course some "issues" (like - accessing elements via getElementsByName, maybe having the script called before the <input>, but let's blame that on copy-pasting ;)) As such, on my IE, running in document mode 8 the alert successfully displays 9.
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>
I am trying out this simple code which is supposed to shift the focus to another text box when a right click is detected on the first, so that any subsequent paste event makes the text to be pasted into the 2nd box:
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$("#real").bind("contextmenu",function() {
$("#paste").focus();
});
});
</script>
</head>
<body>
<input type = 'text' sh = '0' right = '0' id = 'real' />
<input type = 'text' id = 'paste' />
<p>Dummy</p>
</html>
In Opera above versions 12, it is working fine. However, in 11 and below, even though the focus does get shifted to the 2nd text box on right clicking on the first, the paste event pastes the text in the first textbox (with the focus being shifted to the 2nd textbox immediately, on its own). I tried to replace the code by setTimeout(function() { $("#paste").focus(); },0);, still the error persists.
Can anyone tell me how do I fix this, so that the text gets pasted in the 2nd textbox? (Detecting a mouseup, checking whether it's a right click through event.which, if so, shift the focus - yeah, I did that too, same result!)
As an alternative solution...
$("#real").bind("contextmenu",function() {
$("#paste").val($(this).val());
$(this).val('');
});
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/
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 ;)