I'm trying to edit data held in a table and choosing to use contentEditable on divs inside the <td>s, and I'm running into a really weird issue. When I go to edit it the first time, I have to click in twice, every other time after that I only have to click in once. But on the first attempt to edit I have to click in twice. Here is an example table row from my HTML:
<tr style="width:100%"> <td><div class="results" onblur="blurMe(event)" onclick="darkenBox(event)" onkeypress="enterKey(event)" >Adam McGurk</div></td><td><div class="results" onblur="blurMe(event)" onkeypress="enterKey(event)" onclick="darkenBox(event)">amcgurk#shinesolar.com</div></td><td class="delete-sales-person"><span class="delete-icon"></span></td></tr>
And here is the appropriate JS:
//Only to be used with changing data to gray on click and border on hover.
function darkenBox(e){
const ele = e.path[0];
ele.setAttribute("contenteditable", true);
console.log("Editing cell data");
ele.classList.add("darkenBox")
}
// Allows user to edit content by click
function clickEdit(e) {
e.path[0].setAttribute("contenteditable", true);
}
//Deleted placeholder text on click
function clearText(e) {
const ele = e.path[0];
ele.setAttribute("contenteditable", true);
ele.innerText='';
}
// Allows user to stop editing by pressing the, "Enter" key.
function enterKey(e){
const keyCode = e.keyCode;
const ele = e.path[0];
if (keyCode === 13) {
ele.classList.remove("darkenBox");
ele.setAttribute("contenteditable", false);
}
}
function blurMe(e) {
const editedElement = e.path[0];
editedElement.classList.remove("darkenBox");
}
Why is it requiring me to click it twice to edit the first time?
The first time you click it, it sets contenteditable to true. Clicking away doesn't unset that. The second time you click, contenteditable is still true. This allows you to activate the element and edit it right away. If you want to edit it on the first click, you can have all elements you intend to edit start with contenteditable enabled. Or, you can focus the element after enabling contenteditable.
ele.setAttribute("contenteditable", true);
ele.focus();
On an unrelated note, this currently doesn't work at all on firefox and I recommend that you use e.target instead of e.path[0].
Your divs start without contenteditable set. When you click on them (the first time) you set contenteditable to true, but the click is already handled so it won’t trigger an edit.
Only on the next click is the browser gonna allow for edit as now contenteditable is true.
Set contenteditable to true directly in the html and should work.
Related
Take this HTML code, if you place your cursor on the 1st text-box, and then press Tab Key. The cursor will automatically jump to the 2nd text-box.
Box1:
<textarea id='box' cols='60' rows='10'></textarea>
Box2:
<textarea id='box' cols='60' rows='10'></textarea>
I need to replace this default action of switching to the next textbox with execution of JavaScript function I've defined. Let's say: instead of switching textboxes execute function that writes 'a' on the the 1st text-box upon pressing Tab inside the box.
Any idea how I can make this happen?
You would need to listen to the keydown event (tested the others they do not work for this specific case). From there you need to check if tab was pressed. Then you would need to prevent the default from happening and finally execute your custom logic. In the example down below the default functionality of tab is only then overwritten if the first textarea is focussed.
<textarea id="box1"></textarea>
<textarea id="box2"></textarea>
document.getElementById("box1").addEventListener("keydown", (event) => {
if (event.keyCode === 9) {
event.preventDefault();
event.target.value += "a"; // adding a to textarea (your example)
}
})
I'm trying to build a functionality that allows keyboard tabbing between two buttons (CodePen below). More specifically I would like the user to be able to tab onto "button1" and on tab, jump to "button2" and then on tab jump back to button 1.
My solution is to put an event listener on "button1" and listen for a tab keyboard event. When that is triggered, use JQuery's focus() method to shift focus to "button2". On "button2" there is an identical listener that listens for tab event and shift focus back to "button1".
The problem is that when I tab onto "button1", the listener records focus and tab event and shift focus onto "button2" which in turn records focus and tab event and shift it back to "button1" again, creating an infinite loop.
Could I please get suggestions in how to solve this problem?
The real world application of this would be to restrict tabbing within a specific module or section of a page.
Thanks!
Steve
https://codepen.io/steveliu7/pen/WOoMJY
var $button1 = $('.b1');
var $button2 = $('.b2');
var checkButton = function(event) {
if ($button1.is(':focus') && event.which === 9){
console.log($(this))
$('.b2').focus();
return;
};
if ($button2.is(':focus') && event.which === 9){
console.log($(this))
$('.b1').focus();
return;
};
}
$('button').on('keydown', checkButton);
You want to restrict tab navigation between two buttons.
Note that it won't restrict screenreaders navigation to those two buttons.
You have to consider TAB navigation but also SHIFT+TAB navigation
On a purely technical point of view event.preventDefault() is what your are searching for:
var checkButton = function(event) {
if (event.which === 9) {
if ($button1.is(':focus')) {
$button2.focus();
event.preventDefault();
} else if ($button2.is(':focus')){
$button1.focus();
event.preventDefault();
}
}
}
I think what you are trying to do can be achieved much easier with the tabindex property in HTML. If you want to restrict tabbing to certain elements only, you can set tabindex="-1" for those elements that you do not want focused.
Source: https://www.w3schools.com/tags/att_global_tabindex.asp
I have an ASP.NET page with a Telerik RadEditor (rich text box). When tabbing through a page, when a user gets to the text box, focus gets set to the various toolbar icons before it goes to the textarea. I added some jQuery to one page to set the focus on the text area when tabbing out of the last cell on a form:
$('input[type=text][id*=tbCost]').keydown(function (e) {
var keyCode = e.keyCode || e.which;
if (keyCode == 9) { //If TAB key was pressed
e.preventDefault();
var editor = $('body').find("<%=RadEditor1.ClientID%>"); //get a reference to RadEditor client object
editor.setFocus(); //set the focus on the the editor
}
});
I am looking for a way to implement this functionality in the control so that it will work regardless of the page it is on. For example, in the above code, focus is only set if the user is tabbing out of the tbCost cell. I would like to be able to set the focus to the text area when a user tabs into the toolbar items.
Is there any way to detect when an element is about to get focus? I know I can see if an element has focus, but I can't think of a way to implement this functionality.
Thanks
Solution:
If anybody has this same question in the future and wants an example, here is the code I used:
$(document).ready(function () {
$('.reToolCell').focusin(function () {
var editor = $('body').find("<%=RadEditor1.ClientID%>");
editor.setFocus();
});
});
You might consider binding to a focus on the toolbar icons and redirecting focus to the text area. Although this might have unintended side effects if users are trying to tab-focus these tools in order to use them.
//on focus eventHandler for all your icons that calls a function
#('.elementtype, class or a generic way of identifying the icons'.onfocus(myFunction(this))
//the function take a parameter of your element, moves to the next sibling element and sets the focus
myFunction = (element) {
element.next().focus();
}
Our website involves some javascript that produces overlay modal windows.
There is one accessibility problem with this though, once the modal is triggered, the focus is still on the trigger element and not on the modal itself.
These modals can include all sorts of html elements, headings, paragraphs and form controls. What I would like is the focus to begin on the first element within the modal, so most likely to be a h4 tag.
I have explored using the focus() function however this does not work with a number of html elements.
One thought was to add an empty a tag in the window which could gain the focus, but I am unsure about this method.
very late to the party, but the existing answers do not respect accessibility.
The W3C wiki page on accessible modals offers more insight than what's asked in the OP, the relevant part is having tabindex=-1 on the modal container (which should also have an aria-dialog attribute) so it can get :focus.
This is the most accessible way of setting the focus on the modal, there is also more documentation about keeping it in the modal only - and returning it to the element that triggered the modal - quite a lot to be explained here, so I suggest anyone interested to check the link above.
You can append textbox to the beginning of the modal HTML, set focus then hide the textbox. Should have the desired effect as far as I understand your needs.
You could try to blur() the element that has the focus.
to trap focus inside the modal I have used this approach. So the basic idea behind it is exactly to trap the focus in the modal HTML elements and not allowing it to go out of the modal.
// add all the elements inside modal which you want to make focusable
const focusableElements =
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
const modal = document.querySelector('#exampleModal'); // select the modal by it's id
const firstFocusableElement = modal.querySelectorAll(focusableElements)[0]; // get first element to be focused inside modal
const focusableContent = modal.querySelectorAll(focusableElements);
const lastFocusableElement = focusableContent[focusableContent.length - 1]; // get last element to be focused inside modal
document.addEventListener('keydown', function(e) {
let isTabPressed = e.key === 'Tab' || e.keyCode === 9;
if (!isTabPressed) {
return;
}
if (e.shiftKey) { // if shift key pressed for shift + tab combination
if (document.activeElement === firstFocusableElement) {
lastFocusableElement.focus(); // add focus for the last focusable element
e.preventDefault();
}
} else { // if tab key is pressed
if (document.activeElement === lastFocusableElement) { // if focused has reached to last focusable element then focus first focusable element after pressing tab
firstFocusableElement.focus(); // add focus for the first focusable element
e.preventDefault();
}
}
});
firstFocusableElement.focus();
you can find it here trap focus inside the modal
I have a text area and a "add" button on a form. By default the text area is shown as shrinked and grayed out. On focus it will be highlighted by changing the style. On blur it should go back to previous state. Along with highlighting the textarea, add note should toggle as visible and hidden. The problem is when i enter the data in text area and click on the add button, the blur event is hiding the add button and the event on the add button is never triggered.. any solution??
It seems like my question is not clear...
The solution is something like execute the blur event except that the next focused element is not the "add" button...
If there is text entered is it safe to assume you don't want to toggle the button because the user has the intention of entering a note? If so you could do something like:
$(textBox).blur(function() {
if($(this).val().length == 0) {
//change the style
//hide the button
}
})
You need to unhighlight your textarea and hide the "add" button only if there is nothing entered in the textarea:
$('textarea').blur(function() {
if($(this).val() != '') {
// unhighlight textarea
// hide "add" button
}
});
This way the user always sees the field and button if they actually entered something into it, regardless of whether it has focus or not.
Put a small delay between the focus leaving the textbox and the button being hidden, e.g.
function textBox_blur(evt)
{
window.setTimeout(
function() { button.style.display = 'none'; },
200 // length of delay in milliseconds
);
}
This will leave enough time for the click to process (though you might want to play with the length of the delay)