Js Keyboard listening - javascript

my goal to this one is when u type the search bar will pop up the code below is working but i have a problem while typing into different input for example the comment input the js listen and open the search bar. is it possible when im already in a different input field the search will not pop up and show.
<style>
#searchBar { display: none; -webkit-transition: width 2s; /* Safari */ transition: width 2s;}
.search { width: 250px; height: 20px; }
</style>
<script>
window.onload = function() {
var listen = /^[a-z0-9]+$/i;
var searchInput = document.getElementById('searchInput');
var searchBar = document.getElementById('searchBar');
if ( window.addEventListener )
window.addEventListener( 'keyup', insertKey, false);
function insertKey( e ) {
// Get the character from e.keyCode
var key = String.fromCharCode( e.keyCode ).toLowerCase();
// Match the character
if( key.match(listen) ) {
// Change display: none; to display: block;
searchBar.style.display = "block";
// Append every new character
searchInput.value += key;
// Focus on input
searchInput.focus();
// Since you focused on the input you don't need to listen for keyup anymore.
window.removeEventListener( 'keyup', insertKey );
// I didn't tested with jQuery
// $('#searchBar').fadeIn();
// $('#searchBar input').append(keys);
// $('#searchBar input').focus();
}
}
};
</script>

When you add an event listener to window for the keyup event, it will trigger when a keyup is detected no matter where it originates from. You aren't being discriminatory enough about what events you're listening to.
One solution is to add the event listener directly to the input elements, so that a keyup from one element doesn't trigger another element's listener:
document.getElementById("searchInput").addEventListener("keyup", searchInputKeyHandler);
document.getElementById("commentInput").addEventListener("keyup", commentInputKeyHandler);
// etc.
This works but is a bit weird. If all you're doing is listening for a user typing in an input HTML element, then a better event to listen for is input which triggers whenever an input element has its value changed.
document.getElementById("searchInput").addEventListener("input", searchInputKeyHandler);
document.getElementById("commentInput").addEventListener("input", commentInputKeyHandler);
// etc.
Some elements can also listen for a change event; do some research and see what event is most appropriate for your use case.

Related

Prevent function execution twice within two triggered events

I have the following code:
myInput.change(function (e) { // this triggers first
triggerProcess();
});
myButton.click(function (e) { // this triggers second
triggerProcess();
});
The problem with the above is when I click myButton both events are triggered and triggerProcess() is fired twice which is not desired.
I only need triggerProcess() to fire once. How can I do that?
Small demo
You can have a static flag that disables any more triggers once the first trigger has occurred. Might look something like this:
var hasTriggered = false;
myInput.change(function (e) { // this triggers first
triggerProcess();
});
myButton.click(function (e) { // this triggers second
triggerProcess();
});
function triggerProcess () {
// If this process has already been triggered,
// don't execute the function
if (hasTriggered) return;
// Set the flag to signal that we've already triggered
hasTriggered = true;
// ...
}
For resetting the hasTriggered flag, that's entirely up to you and how this program works. Maybe after a certain event occurring in the program you'd want to reenable the ability to trigger this event again — all you'd need to do it set the hasTriggered flag back to true.
You can use the mousedown event, which will fire before the input is blurred, and then check if the input has focus by checking if it's the activeElement, and if it does have focus, don't fire the mousedown event, as the change event will fire instead.
Additionally, if you want a mousedown event to occur when the value hasn't changed, and the change event doesn't fire, you'll need a check for that as well
var myInput = $('#test1'),
myButton = $('#test2'),
i = 0;
myInput.change(function(e) { // this triggers first
$(this).data('prev', this.value);
triggerProcess();
});
myButton.mousedown(function(e) { // this triggers second
var inp = myInput.get(0);
if (document.activeElement !== inp || inp.value === myInput.data('prev'))
triggerProcess();
});
function triggerProcess() {
console.log('triggered : ' + (++i))
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="test1">
<br />
<br />
<button id="test2">
Click
</button>
In a fairly typical scenario where you have an input with a button next to ie, eg quick search.
You want to fire when the input changes (ie onblur) but also if the user clicks the button.
In the case where the user changes the input then clicks the button without changing input focus (ie no blur), the change event fires because the text has changed and the click event fires because the button has been clicked.
One option is to debounce the desired event handler.
You can use a plugin or a simple setTimeout/clearTimeout, eg:
$('#inp').change(debounceProcess)
$('#btn').click(debounceProcess);
function debounceProcess() {
if (debounceProcess.timeout != null)
clearTimeout(debounceProcess.timeout);
debounceProcess.timeout = setTimeout(triggerProcess, 100)
}
function triggerProcess() {
console.log('process')
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input id="inp">
<button id="btn">Click</button>
Use a real <button>BUTTON</button>. If you click on input text, alert is triggered, then once you leave the input text to click anywhere else, that unfocuses the input text which triggers the change event, so now 2 events have been triggered from the text input.
This is an assumption since the code provided is far from sufficient to give a complete and accurate answer. The HTML is needed as well as more jQuery/JavaScript. What is myInput and myButton actually referring to, etc.?
So I bet if you change...
var myButton = $('{whatever this is}'); and <input type='button'>
...TO:
var myButton = $("button"); and <button></button>
...you should no longer have an event trigger twice for an element.
This is assuming that triggerProcess() is a function that does something that doesn't manipulate the event chain or anything else involving events. This is an entirely different ballgame if instead of click() and change() methods you are using .trigger() or triggerHandler(), but it isn't. I'm not certain why such complex answers are derived from a question with very little info...?
BTW, if myInput is a search box and myButton is the button for myInput, as freedomn-m has mentioned, simply remove:
myButton.click(...
Leave myButton as a dummy. The change event is sufficient in that circumstance.
SNIPPET
var xInput = $('input');
var xButton = $('button'); //«———Add
xInput.on('change', alarm);
xInput.on('click', alarm);
xButton.on('click', alarm);
function alarm() {
return alert('Activated')
}
/* For demo it's not required */
[type='text'] {
width: 5ex;
}
b {
font-size: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id='f1' name='f1'>
<input type='text'>
<input type='button' value='BUTTON TYPE'>
<label><b>⇦</b>Remove this button</label>
<button>BUTTON TAG</button>
<label><b>⇦</b>Replace it with this button</label>
</form>

Focus / blur events on contenteditable elements

I'm trying to listen to focus / blur events on span with contenteditable=true attribute.
So here's what I tried (jQuery) :
$('.editable').on('focus',function(){
var that = $(this),
defaultTxt = that.data('default');
that.html('');
});
$('.editable').on('blur',function(){
var that = $(this),
defaultTxt = that.data('default');
if(that.html() === ''){
that.html(defaultTxt);
}
});
But he doesn't seem to work, because span doesn't handle focus / blur. How can I achieve that anyway (IE8 support needed) ?
There are two ways to achieve this effect.
Approach 1: focusin and focusout
$('.editable').on('focusin', function() {
// your code here
});
$('.editable').on('focusout', function() {
// your code here
});
focusin and focusout are like focus and blur events, but unlike the latter, they are fired on almost(?) every element, and also bubble. focusin and focusout are a part of DOM level 3 Specification. Firefox 51 and older didn't support this due to a known bug, but Firefox 52 and above have full support.
Approach 2: click and focus
This only works if you have other focusable elements around your span. What you do is basically use the focus event on any other element as a blur handler.
$('.editable').on('click', function() {
// your code here
});
$('*').on('focus', function() {
// handle blur here
// your code here
});
I wouldn't recommend this approach in a large webapp, because browser performance will take a hit.
I have created a demo for you:
$('.editable').bind('click', function(){
$(this).attr('contentEditable',true);
});
$('.editable').bind('focus', function() {
var that = $(this);
//defaultTxt = that.data('default');
that.html('');
});
$('.editable').bind('blur', function() {
var that = $(this);
var defaultTxt = that.data('default');
if(that.html() === ''){
that.html(defaultTxt);
}
});
.editable{
padding: 5px;
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<span class="editable" data-default="default">Some text</span>
I have changed your code, take a look it. Also now it's keeping the old value when lost the focus if you don't type anything.

Detect any mouse event in the page using JavaScript

I want to write in Javascript a generic eventListener for any possible mouse event.
I am trying to write an eventListener that handles any mouse moves inside the webpage, presses of any kind, scrolling and everything that can be done using the mouse.
I didn't find a good way to do it, also because I need it to be done using pure Javascript without jQuery or any other libraries, just using simple DOM elements and function.
Can anyone show me how it is done by writing one good handler (and not a handler for each possible event)?
What you can do is add event listeners for all mouse events but use the same handler function. Something like this:
function bindEventsToSameHandler(element, events, handler) {
for(var i = 0; i < events.length; i++) {
element.addEventListener(events[i], handler);
}
}
// ...
// usage
var element = document.getElementById('selector'); // select the element on which to handle mouse events
var events = ['click', 'mouseup', 'mousedown']; // add mouse events you want to handle
bindEventsToSameHandler(element, events, function() {
// your handler code goes here
});
Note: this would work for any event, not just the ones related to the mouse.
Here's an example:
function bindEventsToSameHandler(element, events, handler) {
for(var i = 0; i < events.length; i++) {
element.addEventListener(events[i], handler);
}
}
// usage
element = document.getElementById('capture');
events = ['click', 'dblclick', 'mouseup', 'mousedown']; // add your events here
bindEventsToSameHandler(element, events, function(e) {
console.debug('handled ' + e.type);
});
#capture {
width: 100%;
height: 100%;
border: 1px solid black;
padding: 100px;
}
<body>
<p id='capture'>CAPTURE EVENTS BOX</p>
</body>

Resize event on multiple select control

I have a multiple select html element.
I want to catch the resize event, so I can store the latest value.
<select multiple="multiple" class="ra-multiselect-collection" style="resize: vertical; margin-top: 0px; margin-bottom: 5px; height: 527px;"></select>
The following code doesnt work:
$('.ra-multiselect-collection').on( 'resize', function(){
alert('resized');
});
Any ideas?
Well, I don't think that you can bind a resize event to a DOM element, but check this out:
$("select").on("mouseup", function()
{
var el = $(this);
if (el.data("old-height") == null || el.data("old-height") != el.height())
{
alert("resized!");
}
el.data("old-height", el.height());
}).data("old-height", $("select").height());
Fiddle
I have used mouseup event checking the old height stored in a data property with the current height on the moment of the event. If they are different, you get a resize event. Not a pretty beautiful workaround, but it seems to work.
I could not test on IE because it doesn't support that property and on Firefox, it works nice but it seems that you can double-click the resize corner and it returns to the initial size and this doesn't trigger the event actually.
In your case, as you're using a class to select those elements, you can do this:
$(".ra-multiselect-collection").each(function()
{
$(this).on("mouseup", function()
{
var el = $(this);
if (el.data("old-height") == null || el.data("old-height") != el.height())
{
alert("resized!");
}
el.data("old-height", el.height());
}).data("old-height", $(this).height());
});
Didn't tested but it should work.
Finally I used resizable function from jQuery UI
http://jqueryui.com/resizable/
This is my code:
$('.ra-multiselect-collection').first().resizable({
resize: function() {
alert('resized');
}
});
Maybe that .first() isn't necessary
You dont have resize event here, but u can store the size on mousedown event, and check if it changed on mouseup event

checkbox button does not work well when clicked on quickly multiple times

I have a jsfiddle Here: http://jsfiddle.net/zAFND/616
Now if you open up fiddle in IE (I use IE9) and firefox, if you double click on a check box button, it turns it on but does not turn it off. But if you open it up in opera, safarai and chrome, it works fine if you double click or click in quick succession.
My question is how to allow quick succession clicks to work correctly in firefox and IE9?
Code:
HTML:
<div id="ck-button"><label>
<input type="checkbox" name="options[]" id="optionA" value="A" /><span>A</span></label>
</div>
CSS:
#ck-button {
margin:8px;
background-color:#EFEFEF;
border:1px solid #D0D0D0;
overflow:auto;
float:left;
position: relative;
}
#ck-button label {
float:left;
width:4.0em;
cursor:pointer;
}
#ck-button label span {
text-align:center;
padding:3px 0px;
display:block;
}
#ck-button label input {
position:absolute;
top:-20px;
}
#ck-button input:checked + span {
background-color:green;
color:white;
}
Jquery/javasscript:
$(document).ready(function(){
$("body").css("-webkit-user-select","none");
$("body").css("-moz-user-select","none");
$("body").css("-ms-user-select","none");
$("body").css("-o-user-select","none");
$("body").css("user-select","none");
});
This is a bug in Firefox. See Bug 608180 - Double/rapid clicking a checkbox label does not work as expected
IE has, for historical reasons (but fixed in more recent versions), a bugged event model that skips the second mousedown and click events on a double click. See bug 263 - beware of DoubleClick in IE.
I've made a plugin that fixes some bugs in jQuery UI button widget as well as working around the Firefox bug not long ago, shouldn't be hard to adapt it to your non-jQuery UI buttons.
Extracted the important part and adapted it for nested checkboxes inside labels:
(function () {
var mdtarg, //last label mousedown target
mdchecked, //checked property when mousedown fired
fixedLabelSelector = '.fixedLabelCheckbox'; //edit as you see fit
$(document).on('mousedown', fixedLabelSelector, function (e) {
//only left clicks will toggle the label
if (e.which !== 1) return;
mdtarg = this;
mdchecked = this.control ? this.control.checked : $(this).find('input')[0].checked;
//reset mdtarg after mouseup finishes bubbling; prevents bugs with
//incorrect mousedown-mouseup sequences e.g.
//down IN label, up OUT, down OUT, up IN
$(document).one('mouseup', function () {
mdtarg = null;
});
}).on('mouseup', fixedLabelSelector, function (e) {
if (e.which !== 1) return;
if (mdtarg === this) {
var ch = this.control || $(this).find('input')[0];
//the click event is supposed to fire after the mouseup so
//we wait until mouseup and click finish bubbling and check if it
//had the desired effect
setTimeout(function () {
if (mdchecked === ch.checked) {
//else patch it manually
ch.checked = !ch.checked;
$(ch).change();
}
}, 0);
}
});
}());
Fiddle tested in Firefox.
You have to add the fixedLabelCheckbox class to all labels containing checkboxes that you'd like to fix with the code above.
It will work regardless of where you put the script and it also fixes dynamically added checkboxes as long as the label has the corresponding delegated class/selector.
Note that if you're using other libraries, this may not fire the change handlers bound outside of jQuery.
If you don't feel like adding extra classes to your markup, you can use this version (more code and less performance):
(function ($) {
function getControl(lbl) { //fallback for non-HTML5 browsers if necessary
return lbl.control || (lbl.htmlFor ? $('input[id="'+lbl.htmlFor+'"]')[0] : $(lbl).find('input')[0]);
}
var mdtarg, //last label mousedown target
mdchecked; //checked property when mousedown fired
$(document).on('mousedown', 'label', function (e) {
//only left clicks will toggle the label
if (e.which !== 1) return;
var ch = getControl(this);
if (!ch || ch.type !== 'checkbox') return;
mdtarg = this;
mdchecked = ch.checked;
//reset mdtarg after mouseup finishes bubbling; prevents bugs with
//incorrect mousedown-mouseup sequences e.g.
//down IN label, up OUT, down OUT, up IN
$(document).one('mouseup', function () {
mdtarg = null;
});
}).on('mouseup', 'label', function (e) {
if (e.which !== 1) return;
if (mdtarg === this) {
var ch = getControl(this);
//the click event is supposed to fire after the mouseup so
//we wait until mouseup and click finish bubbling and check if it
//had the desired effect
setTimeout(function () {
if (mdchecked === ch.checked) {
//else patch it manually
ch.checked = !ch.checked;
$(ch).change();
}
}, 0);
}
});
}(jQuery));
Fiddle
As you can see from the code above, this version should work with both label's for attribute as well as nested inputs inside the label, without adding any extra markup.
About disabling selection: you can either put the user-select in the CSS as commented in your question, or, if browsers that don't support the user-select are also concerned, apply this answer on all labels that you want to have selection disabled.
You could add browser detection and then, if IE or Firefox, add the ondblclick event via JS to invert the checkbox.
You can't just set it unconditionally, since some browsers (Safari, Chrome) transmit two clicks and a dblclick, while others (IE, Firefox) transmit only one click and one dblclick. On the former, the two click events will invert the field twice. On the latter, only one click event fires and thus the field is only inverted once; to mitigate this, you need to make dblclick invert the field so that two clicks invert it an even number of times.
Hope this helps!!

Categories