How do a get buttons not to take the focus? - javascript

I want my (ExtJS) toolbar buttons not to grab the focus on the web page when they are clicked, but to do their "thing" while leaving the focus unchanged by the click. How do I do that?

Cancelling the default behavior of onmousedown prevents an element from getting the focus:
// Prevent capturing focus by the button.
$('button').on('mousedown',
/** #param {!jQuery.Event} event */
function(event) {
event.preventDefault();
}
);

document.activeElement stores the currently focussed element.
So on your toolbar, you can add a "mousedown" handler to this function :
function preventFocus() {
var ae = document.activeElement;
setTimeout(function() { ae.focus() }, 1);
}
Try this example :
<html>
<head>
<script>
function preventFocus() {
var ae = document.activeElement;
setTimeout(function() { ae.focus() }, 1);
}
</script>
</head>
<body>
<input type="text"/>
<input type="button" onmousedown="preventFocus()" onclick="alert('clicked')" value="Toolbar" />
</body>
</html>

This usually does the trick for me:
<button
tabindex="-1"
onclick="javascript:console.log('do your thing')"
>My Button</button>
From https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex:
A negative value (usually tabindex="-1") means that the element should be focusable, but should not be reachable via sequential keyboard navigation. It's mostly useful to create accessible widgets with JavaScript.

I don't think there's an easy way to do what you want to do because it's the browser's default behaviour.
You could of course blur() the button as soon as it is clicked, but that would simply unselect everything. To have the previously active object regain focus, you'd have to create a "memory" of sorts by adding a blur handler for every element to keep track of which element had/lost focus last (store the id of the element in a global and update it when an element loses focus).

The top-voted answer is technically correct, but depends on jQuery...
Here's a simpler example:
<span onclick="document.execCommand('bold', false);" onmousedown="event.preventDefault();"></span>

My solution is to replace <button /> with <div /> and style it as a button.
Looks like Div doesn't take a focus on it when you click it.

Because the toolbar buttons are just styled ordinary HTML button elements then this is an actual browser behavior, and you should think twice before changing it. But nevertheless...
You should be able to prevent the botton from receiving focus by just returning false from its onclick handler.

Maybe you should try to use stateful and state change properties for form fields or whatever to get focus back?

I would attach one blur event listener to all fields. This listener should save the field, that lost the focus, in a global variable.
Then all the toolbar button should get one focus event listener. This listener should focus the field, that was saved as described above.
This code should work, although it didn't test it

<script>
function focusor(){
document.getElementById('focus').focus;
}
document.onkeydown = focusor;
document.onclick = focusor;
</script>
<div style="width: 0px; height: 0px; overflow: hiddden;">
<button id="focus"></button>
</div>
What I have found, is you will have to make a dummy element, I found buttons to work best in this situation. put the button in a div and make the div 0px.
[do not make the div display none, some browsers will just ignore it]
Basically any click or button presses, it will focus on this dummy button.
I had a project very similar and whenever they pressed the down key it selected the first button on the page, this just focuses on the button over and over again.
Sort of jacked up, but it works.

All these answers are wack. Here's a very excellent trick that only uses CSS
<button type="submit" disabled>
<span>Submit</span> <!-- the <span> is the secret -->
</button>
Now in your css:
button[disabled] > * {
pointer-events: none;
}
The trick is the inner span has to be used, otherwise the button will still steal focus away from inputs.

Related

How to trigger a function from click on document

Here's my situation: I've got a field that once the user double click, it'll edit the field. That's fine and working. I've got two functions: ok and cancel. Cancel disables the editing mode. ATM, the user has to click cancel to disable the editing mode. What I'd like to is to allow the editing mode to be disabled when the user clicks anywhere else on the page. How can I accomplish this with Angular?
EDIT: I'm adding my markup (Note: this is Jade):
tr(ng-repeat="user in users | filter:searchText"s)
td(ng-dblclick="editItem(user)", hm-double-tap="editItem(user)", ng-blur="cancelEditing()")
span(ng-hide="user.editing") {{user.name}}
form(ng-submit="doneEditing(user)", ng-show="user.editing", class="inline-editing-2", ng-blur="cancelEditing()")
input(type="text", class="form-control", ng-model="user.name")
button(class="btn btn-success mr-1", ng-show="user.editing", ng-click="doneEditing(user)")
span(ng-click="doneEditing(user)").fa.fa-check-circle
button(class="btn btn-warning mr-1", ng-show="user.editing", ng-click="cancelEditing(user)")
span(ng-click="cancelEditing(user)").fa.fa-times-circle
As you can see, I've got a hg-repeat on user. When double click on the td element it makes user.editing true so the form shows up. the cancelEditing(user) makes the variable false and only the field is displayed.
I've added ng-blur="cancelEditing()" on thetr,td,spanandform` and none of it worked.
Any ideas what am I missing?
Use ng-blur to bind your cancel event to the element. It will fire when the element loses focus.
IE: <input ng-blur="cancel()" />
Note: The cancel function must be within scope.
Angular ngBlur Docs
Update from comments:
Give the input element focus when your double tab event fires making the field editable. Your blur event is likely not firing because the input element never had focus.
You could do this from inside your editItem function or from inside the directive.
As an example:
yourApp.directive('hmDoubleTap', function(){
return function(scope, element, attr){
if(doubleTap) {
// Fire editItem(user)
// You could add your .focus() inside editItem().
// Or focus the first input element at the end of the directive.
element.find("input")[0].focus();
}
};
});
b1j's answer would work only if the element gains focus. Does hm-double-tap directive focuses the element after double click? If not you will have to trigger focus in editItem function.
Another approach would be to handle the click event on any other element like this:
$('#field-no-edit').click(function() {
$(this).hide();
$('#field-edit').show().focus();
});
$('body').on('click', function(e){
console.log($(e.target).attr('id'));
if ($(e.target).attr('id') != 'field-no-edit') {
console.log('not');
$('#field-no-edit').text($('#field-edit').val());
$('#field-edit').hide();
$('#field-no-edit').show();
}
});
JSFiddle

Moving screen to focused area html5

I've got a html5 form and a submit button(original, I know).
When the user fills out the form incorrectly and presses the html < button ... /> tag, the focus goes to the first error message. This is expected and good behaviour and all is well.
However, when the user presses GO on both chrome and safari the focus does not move.
I tried debugging by printing out the document.activeElement after I set the focus.
It prints the same html element when I press go and when I press the form button, even though the focus is not on this particular element when i press GO.
In short:
Press HTML button - use jquery to apply focus to desired error input. Works like a charm.
Press GO button - use same function to apply focus to the desired error input.
The user does not get anything.
Code examples:
Markup:
<form class="boxBody form" action="#" id="profileForm">
<input type="text" class="keyboardInput" id="customer-email" name="email" tabindex="1" size="28" maxlength="128">
//More inputs
<button id="profileSubmit" data-localize="{'text': 'profileBox.submit'}" tabindex="11" class="save-profile btn btn-red"></button>
</form>
.js:
$('#profileForm').submit(function(event)
{
event.preventDefault();
updateProfile(event);
//updateProfile validates the form and creates error messages
setFocusOnUpdate();
console.log(document.activeElement);
//prints the same dom element.
});
And
function setFocusOnUpdate(){
var successMessage = $(".alert-success:visible", widgetElement);
if( successMessage.length > 0 )
{
//Success message gets focus
widgetElement.find("input, select").last().focus();
}
else
{
//First error message gets focus
var firstVisibleAlert = $(".alert:visible", widgetElement)[0];
$(firstVisibleAlert).parent().find("input, select").focus();
}
}
Thing is, in both instances, GO and < button / >, the desired element gets focus, but the screen only moves to the element when I use the button. How can I get the screen to move when pressing go also?
Can some wizard please help me? Any ideas appreciated!
Have you tried using anchors on the same page to get your desired effect?
Isn't it possible to set anchors by the forms so that when you want the focus to be set too a certain input it does so by moving your screen to the anchor?

How can I put a button in the down state?

Suppose I have a button, which goes into a down state when someone clicks on it, but before the mouse is released.
Now suppose instead that someone presses the 'a' key, I want the button to go into the down state, until the key is released, at which point it is triggered. Is this possible?
After dooing some research here is the final answer I got:
You can trigger mousedown or mouseup events on a button element using keyup and keydown
if your button is programmed to change its style according to these events than you are good to go.
See this fiddle example: http://jsfiddle.net/FwKEQ/15/
Note that if you use jQuery's UI components than it does work. But for standard buttons there is no way that you can move them to their pressed state using javascript
html:
<button id="jQbutton">Press 'A' to move me to pressed state</button>
Javascript:
<script>
$( "#jQbutton" ).button();
$(document).keydown(function(event) {
if ((event.keyCode === 97)||(event.keyCode === 65))
$("#jQbutton").mousedown();
});
$(document).keyup(function(event) {
if ((event.keyCode === 97)||(event.keyCode === 65))
$("#jQbutton").mouseup();
});
</script>
EDIT:
There might be a hack that we could utilize:
using accesskey for the button element and then try to simulate the accesskey press (that i am not sure if possible)
here is where i'm at so far http://jsfiddle.net/FwKEQ/28/
EDIT 2:
So looking further into this topic i have found the following:
Default buttons (without styles) are rendered by the OS, I was not able to find a formal proof for that but if you try to load the same page using a mac OS you'll get mac OS style buttons while in windows you will get the "ugly" gray button.
Because the default buttons are rendered by the OS they comply to OS events meaning events that are sent by the browser and are trusted.
this is not true for custom styled buttons as they comply to CSS an JS to change their appearance on press that is why the JQ button is affected by JS.
so to summarize you would need a trusted press event to fire on a default button to change its style and that cannot be done due to security constraints.
read a bit more about trusted events here: http://www.w3.org/TR/DOM-Level-3-Events/#trusted-events
and if someone could find a formal reference with regards to the default buttons being rendered by the OS please comment or edit this answer.
Unfortunately the rendering of the active state on default buttons neither
is a simple matter of css styling nor can be easily changed by applying
javascript.
An option to do this on default buttons is to use the hotkeys jquery plugin: https://github.com/jeresig/jquery.hotkeys or implement alternative key codes for different browsers.
and to apply 50% opacity to the default button when pressed (to indicate the keydown).
(To me it seems almost perfect ;-) It probably is as good as it can easily get to work across platforms and browsers using default buttons.
jsfiddle DEMO
and the code ...
html:
<button id="test">Test Button</button>
Selected: <span class="selected" id="out"></span>
javascript:
$('#test').click(function () {
fn_up();
});
fn_down = function(event){
$('#test').css("opacity", 0.5);
$('#test').focus();
event.preventDefault();
}
fn_up = function(event){
$('#test').css("opacity", 1);
$('#out').append(" test");
event.preventDefault();
}
//to bind the event to the 'a' key
$(document).bind('keydown','a', fn_down);
$(document).bind('keyup','a', fn_up);
//to get the same effect with the 'space' key
$(document).bind('keydown','space', fn);
$(document).bind('keyup','space', fn2);
In the fiddle I apply it to the space button and the mousedown/up to achieve the same effect with all events (but you could just use it with the 'a' key ... this is a matter of taste).
Here is a jsfiddel that shows how it's done using jQuery: http://jsfiddle.net/KHhvm/2/
The important part:
$("#textInput").keydown(function(event) {
var charCodeFor_a = 65;
if ( event.which == charCodeFor_a ) {
// "click" on the button
$('#button').mousedown();
// make the button look "clicked"
$('#button').addClass('fakeButtonDown');
// do some stuff here...
// release the button later using $('#button').mousedown();
}
});
The button event is triggered when entering "a" in the input field. But as Mark pointed out you need to fake the styling for the clicked button because the browser doesn't do it.
Edit: I'm not sure if you're using jQuery in your project. I just wanted to show that it is possible at all. If it can be done with the jQuery library there is also a way to do it in pure javascript. ;)

jQuery Tools Overlay - Two buttons with different close conditions

I have the following jQuery Tools overlay:
<div id='editDescriptiontOverlay' class='overlay'>
<input type='text' class='description'/>
<button class='save'>Save</button>
<button class='close'>Cancel</button>
</div>
Background info: The HTML for this overlay is static. I have a list of items each having their own Edit link. When a given Edit link is clicked, the overlay is generated by calling: $('a[rel=#editDescriptionOverlay]').overlay( { ... } ); and the input is populated with the respective text.
The Save button needs to validate the text in the input element and close the overlay if and only if the validation is successful. Otherwise, the overlay must remain open. The Cancel button simply closes the overlay without validation.
The validation logic has been independently verified to work.
I've tried setting the onBeforeClose event during overlay generation as a means of validation. Taking this approach, both the Save and Cancel buttons needed the same class .close. Unfortunately, the condition applies to all .close elements in the overlay so even the Cancel button was validating.
I've also tried binding a click event to the Save button immediately after generating the overlay, like so:
$('.save', $('#editDescriptionOverlay'))
.unbind('click')
.bind('click', function() {
if (validateText) {
console.log("Validation passed.");
$('a[rel=#editDescriptionOverlay]').overlay().close();
}
else {
console.log("Validation failed.");
}
});
The console.log's confirm that the validation is working, but the overlay doesn't close.
Any insight is appreciated, thanks.
For jquery widgets, public methods should be called as follows:
$('a[rel=#editDescriptionOverlay]').overlay("close");
wherein close is the method name that you wish to call.
If a method accepts parameters, then, these should be added as parameters right after the method name.
Updated:
I am sorry. I just had time to check what jQuery Overlay Tools is and I am mistaken. This is not similar to any jQuery widget, hence, my comment above will also not work for this case. I tried your code above and it worked. The overlay was closed. But, when I tried it with multiple <a rel="#editDescriptionOverlay">, which I think is what you did. It did not work. My suggestion would be to use just one <a rel="#editDescriptionOverlay"> and use a dummy anchor element for the Edit link, which when clicked would trigger a click to <a rel="#editDescriptionOverlay">. You can do something like this:
<script type="text/javascript">
$(document).bind("ready", function(e){
$("a[rel]").overlay();
$('.save', $('#editDescriptionOverlay')).unbind("click").bind("click", function(){
if (validationValue){
$("a[rel=#editDescriptionOverlay]").overlay().close();
}
});
});
function clickThis(){
$("a[rel=#editDescriptionOverlay]").trigger('click');
return false;
}
</script>
Edit1
Edit2
<a rel="#editDescriptionOverlay">Dummy</a>
<div id='editDescriptionOverlay' class='overlay'>
<input type='text' class='description'/>
<button class='save'>Save</button>
<button class='close'>Cancel</button>
</div>
I'd prefer binding an event to the save button (the second one you mentioned). Actually your code looks fine, except that you probably don't need to bind the event to $('#editDescriptionOverlay') and you have typo in your html markup above (<div id='editDescriptiontOverlay' should be <div id='editDescriptionOverlay').
See here for an example.

How to prevent a popup from closing when clicking on it using jQuery?

I'm creating a jQuery plugin that allows me to easily display a popup. In this case, the trigger element is an input and the target element is a div. So, the functionality is based on the focus and blur event. When the input gets focus, the popup opens and when it gets blur, the popup closes. I need the popup to stay open when I click on it and it closes because of the blur event I have set. I have tried to plug in the jQuery off() function into my custom blur() function within the plugin but it doesn't work.
I want to be able to click inside the popup without closing it, even when the input is on blur state or if someone can provide me with a better approach with in the plugin, that will be great too!
JS code
/*
* Popbox plugin
*/
$.fn.adPopbox = function(target){
return this.each( function() {
var enabler = $(this)
function focus() {
return enabler.focus( function(){
target.addClass('triggered');
});
}
function blur() {
return enabler.blur( function(){
target.removeClass('triggered');
});
}
function popbox() {
return target.click( function(){
target.addClass('triggered');
});
}
focus();
blur();
popbox();
});
}
/*
* Invoke Popbox plugin
*/
$(".popover-trigger").adPopbox($('.popover'));
HTML code
<div class="input-wrapper">
<input type="text" class="popover-trigger">
</div>
<div class="popover">
<p>Content to be showed!</p>
</div>
Here is a preview
You can not use the event blur because when you click outside the input, it is first the blur event that is triggered and then the event click but at that moment, your popup is already hidden and the target is on what is below, ie the body.
You should also use the click event on the document to close the popup by inspiring you with this answer: https://stackoverflow.com/a/3028037/4864628

Categories

Resources