Custom select (dropdown) don't focusing on first element when active - javascript

I'm making a custom dropdown and want to make good keyboard support. How do I get focus on my first LI when the UL visible. Didn't find answer by my self.
I take code from there https://codepen.io/beforesemicolon/pen/abNpjKo
On CodePen focus on first element works. But on my page - no... please, tell me if you know :)
Here is the code:
function DropDown(dropDown) {
const [toggler, menu] = dropDown.children;
const handleClickOut = e => {
if(!dropDown) {
return document.removeEventListener('click', handleClickOut);
}
if(!dropDown.contains(e.target)) {
this.toggle(false);
}
};
const setValue = (item) => {
const val = item.textContent;
toggler.textContent = val;
this.value = val;
this.toggle(false);
dropDown.dispatchEvent(new Event('change'));
toggler.focus();
}
const handleItemKeyDown = (e) => {
e.preventDefault();
if(e.keyCode === 38 && e.target.previousElementSibling) { // up
e.target.setAttribute("aria-selected", "false");
e.target.previousElementSibling.setAttribute("aria-selected", "true");
e.target.previousElementSibling.focus();
} else if(e.keyCode === 40 && e.target.nextElementSibling) { // down
e.target.setAttribute("aria-selected", "false");
e.target.nextElementSibling.setAttribute("aria-selected", "true");
e.target.nextElementSibling.focus();
} else if(e.keyCode === 27) { // escape key
this.toggle(false);
} else if(e.keyCode === 13 || e.keyCode === 32) { // enter or spacebar key
setValue(e.target);
}
}
const handleToggleKeyPress = (e) => {
e.preventDefault();
if(e.keyCode === 27) { // escape key
this.toggle(false);
} else if (e.keyCode === 13 || e.keyCode === 32) { // enter or spacebar key
this.toggle(true);
} else if (e.shiftKey && e.keyCode === 9) { // tab + shift key
this.toggle(false);
document.getElementById("message_email").focus();
} else if (e.keyCode === 9 ) { // tab key
this.toggle(false);
document.getElementById("message_text").focus();
}
}
toggler.addEventListener('keydown', handleToggleKeyPress);
toggler.addEventListener('click', () => this.toggle());
[...menu.children].forEach(item => {
item.addEventListener('keydown', handleItemKeyDown);
item.addEventListener('click', () => setValue(item));
});
this.element = dropDown;
this.value = toggler.textContent;
this.toggle = (expand = null) => {
expand = expand === null ? menu.getAttribute("aria-expanded") !== "true" : expand;
menu.setAttribute("aria-expanded", expand);
if(expand) {
menu.children[0].focus();
toggler.classList.add('active');
menu.children[0].focus();
document.addEventListener('click', handleClickOut);
dropDown.dispatchEvent(new Event('opened'));
//toggler.blur();
} else {
toggler.classList.remove('active');
toggler.focus();
dropDown.dispatchEvent(new Event('closed'));
document.removeEventListener('click', handleClickOut);
}
}
}
const dropDown = new DropDown(document.querySelector('.message__dropdown'));

Heh... problem was in CSS. Property {transition-duration} was written by me for UL (I mean for changing background color, but I didn't choose {transition-property}).
After I remove {transition-duration} focusing is working well. Oh my God... it tooks fore hours

Related

How to toggle the content of an element by pressing a key?

Im currently trying to make a website where if i press q the p tag will change from "Q" to "A". This currently works with the code below. However the problem is that when pressing q it needs to go back to "A". I've tried making it work with removeEventListeners but it doesn't seem to work.
<script>
document.addEventListener("keypress", event => {
if (event.key == "q") {
document.getElementById("P1").innerText = "Q"
}
});
</script>
Like #diegod suggested in the comments you should check which character is currently shown in the p element and change the innerText accordingly:
const p1 = document.getElementById("P1");
document.addEventListener("keypress", event => {
if (event.key == "q") {
if (p1.innerText == "A") {
p1.innerText = "Q";
} else {
p1.innerText = "A";
}
}
});
Using ternary operator example:
const p1 = document.getElementById("P1");
document.addEventListener("keypress", event => {
if (event.key == "q") {
p1.innerText = p1.innerText == "A" ? "Q" : "A";
}
});
const $ = (prop) => document.querySelector(prop)
const changeToQ = () => {
$('p').innerText = 'Q'
}
const reset = () => {
$('p').innerText = 'A'
}
document.addEventListener('keydown', (e) => {
if (e.key === 'q') changeToQ()
})
document.addEventListener('keyup', (e) => {
if (e.key === 'q') reset()
})
I think this is what are you looking for
have your tried to make else statement
else{ document.getElementById("P1").innerText = "A"}

JavaScript - The function only execute after set breakpoint

Here is my jQuery for dynamic attached elements. The jq-select-ring button can be multiple on the DOM. Basically, it was attached through an Ajax call.
let cKeyTabShift = false;
$("body").on("keydown", ".jq-select-ring", function (e) {
if (!isMobileSite) {
var keyCode = (e.keyCode ? e.keyCode : e.which);
if (keyCode == 9) {
if (e.shiftKey) {
cKeyTabShift = true;
} else {
cKeyTabShift = false;
}
}
}
});
$("body").on("focusout", ".jq-select-ring", function () {
if (!isMobileSite) {
const parentIndex = $(this).closest('.flex-item').index();
const $elmSliders = $(this).closest('.container').find("div[id^='touchCarousel-'][role='tabpanel']");
const $nextArrow = $(this).closest('.touch-carousel').find('.touchcarousel-next');
const $prevArrow = $(this).closest('.touch-carousel').find('.touchcarousel-prev');
if (typeof ($elmSliders) != "undefined" && $elmSliders.length > 0) {
if ($elmSliders.length > 1) {
if (parentIndex == 1 && cKeyTabShift == false) {
if (!$nextArrow.hasClass('endArrows')) {
$nextArrow.trigger('click');
}
}
if (parentIndex == 0 && cKeyTabShift == true) {
if (!$prevArrow.hasClass('endArrows')) {
$prevArrow.trigger('click');
cKeyTabShift = false;
}
}
}
}
}
});
The issue is the trigger click is called when I add breakpoint only.
$nextArrow.trigger('click');
$prevArrow.trigger('click');

Javascript keydown event doesn´t give me the char # in EDGE

I'm working in a mentioning directive, basically when the user is typing in the input field ( a div with contentEditable=true in this case ), is gonna display a list of user for then insert the name of the user in a specific format, now the list is gonna displayed after the user press #, for chrome and firefox work just great but for EDGE and IE ( unfortunately i need to support ) doesn't work because in this case the # apparently doesn't exist.
now for the key press I'm using the #HostListener('keydown', ['$event'])
HostListener
#HostListener('keydown', ['$event']) keyHandler(event: any, nativeElement: HTMLInputElement = this._element.nativeElement) {
let val: string = getValue(nativeElement);
let pos = getCaretPosition(nativeElement, this.iframe);
let charPressed = this.keyCodeSpecified ? event.keyCode : event.key;
if (!charPressed) {
let charCode = event.which || event.keyCode;
if (!event.shiftKey && (charCode >= 65 && charCode <= 90)) {
charPressed = String.fromCharCode(charCode + 32);
} else if (event.shiftKey && charCode === KEY_2) {
charPressed = this.triggerChar;
} else {
charPressed = String.fromCharCode(event.which || event.keyCode);
}
}
if (event.keyCode == KEY_ENTER && event.wasClick && pos < this.startPos) {
// put caret back in position prior to contenteditable menu click
pos = this.startNode.length;
setCaretPosition(this.startNode, pos, this.iframe);
}
// console.log('=== keyHandler', this.startPos, pos, val, charPressed, event);
this.triggerList(event, charPressed, nativeElement, val, pos);
}
Now as you can see I'm using event.keycode and event.key to get the key from the event keydown, I pass does values to the method this.triggerList()
that basically is gonna display the list of mentions options if and only if the user press # that is the trigger char ( this.triggerChar ).
TriggerList Method
private triggerList(event, charPressed, nativeElement, val, pos): any {
if (charPressed == this.triggerChar) {
this.startPos = pos;
this.startNode = (this.iframe ? this.iframe.contentWindow.getSelection() : window.getSelection()).anchorNode;
// console.log('=== HERE CHAR', this.startNode, this.startPos);
// check if mentioning is allowed based on the text before the mention start char
if (!this.configService.appConfig.platform.EDGE) {
let position = this.getHtmlCaretPosition(nativeElement);
const charBefore = val[position - 1];
if (charBefore == undefined || charBefore.trim() == '' || charBefore == ':') {
this.log.trace('Start mentioning');
this.stopSearch = false;
this.searchString = null;
this.showSearchList(nativeElement);
this.updateSearchList();
}
} else {
this.stopSearch = false;
this.searchString = null;
this.showSearchList(nativeElement);
this.updateSearchList();
}
} else if (this.startPos >= 0 && !this.stopSearch) {
if (pos <= this.startPos) {
this.searchList.hidden = true;
}
// ignore shift when pressed alone, but not when used with another key
else if (event.keyCode !== KEY_SHIFT && !event.metaKey && !event.altKey && !event.ctrlKey && pos > this.startPos) {
if (event.keyCode === KEY_SPACE) {
this.startPos = -1;
} else if (event.keyCode === KEY_BACKSPACE && pos > 0) {
pos--;
if (pos == 0) {
this.stopSearch = true;
}
this.searchList.hidden = this.stopSearch;
} else if (!this.searchList.hidden) {
if (event.keyCode === KEY_TAB || event.keyCode === KEY_ENTER) {
this.stopEvent(event);
this.searchList.hidden = true;
// value is inserted without a trailing space for consistency
// between element types (div and iframe do not preserve the space)
let textValue = this.mentionSelect(this.searchList.activeItem);
insertValue(nativeElement, this.startPos, pos, textValue, this.iframe);
this.emitSelection(nativeElement);
if (this.htmlStyling) {
let quillElement = document.querySelector('.ql-editor');
let innerHtml = quillElement.innerHTML;
let strings = innerHtml.split(textValue);
if (strings.length === 2) {
innerHtml = `${strings[0]}<span id="mention${textValue.substring(1)}${strings.length - 1}" style="color: #0065FF; background: rgba(0,101,255,.2)">${textValue}</span> ${strings[1]}`;
} else {
let openSpan = false;
innerHtml = strings.reduce((total, current, currentIndex) => {
if (current.indexOf(`mention${textValue.substring(1)}`) > 0) {
return `${total}${openSpan ? '</span> ' : ''}${current}${textValue}`;
} else if (openSpan) {
return `${total}</span> ${currentIndex < strings.length - 1 ? current + textValue : current}`;
} else {
openSpan = true;
return `${total}${current}<span id="mention${textValue.substring(1)}${strings.length - 1}" style="color: #0065FF; background: rgba(0,101,255,.2)">${textValue}`;
}
}, '');
}
quillElement.innerHTML = innerHtml;
// tslint:disable-next-line:no-angle-bracket-type-assertion
let mentionElement: HTMLInputElement = document.getElementById(`mention${textValue.substring(1)}${strings.length - 1}`) as HTMLInputElement;
// tslint:disable-next-line:no-angle-bracket-type-assertion
setCaretPosition(mentionElement.nextSibling as HTMLInputElement, 1);
}
// fire input event so angular bindings are updated
if ('createEvent' in document) {
let evt = document.createEvent('HTMLEvents');
evt.initEvent('input', false, true);
nativeElement.dispatchEvent(evt);
}
this.startPos = -1;
return false;
} else if (event.keyCode === KEY_ESCAPE) {
this.stopEvent(event);
this.searchList.hidden = true;
this.stopSearch = true;
return false;
} else if (event.keyCode === KEY_DOWN) {
this.stopEvent(event);
this.searchList.activateNextItem();
return false;
} else if (event.keyCode === KEY_UP) {
this.stopEvent(event);
this.searchList.activatePreviousItem();
return false;
}
}
if (event.keyCode === KEY_LEFT || event.keyCode === KEY_RIGHT) {
this.stopEvent(event);
return false;
} else {
let mention = val.substring(this.startPos + 1, pos);
if (event.keyCode !== KEY_BACKSPACE) {
mention += charPressed;
}
this.searchString = mention;
this.searchTerm.emit(this.searchString);
this.updateSearchList();
}
}
}
}
now the issue here is that if the user to insert the char # need to use the combination of ALT + Q EDGE only detect ALT and then Q, compare to firefox and chrome that with the combination ALT + Q detect # for this reason the list is not display because the char never match.
First i replace the event keydown for keypress, then where i save the char in the variable charPress i create a condition to check if the browser is EDGE or IE, and get char code using event.charCode and convert it in to string using String.fromCharCode(event.charCode) at the end looks like this.
#HostListener('keypress', ['$event']) keyHandler(event: any, nativeElement: HTMLInputElement = this._element.nativeElement) {
let val: string = getValue(nativeElement);
let pos = getCaretPosition(nativeElement, this.iframe);
let charPressed = this.keyCodeSpecified ? event.keyCode : event.key;
if (this.configService.appConfig.platform.EDGE) {
charPressed = String.fromCharCode(event.charCode);
}
......

Detecting two keyboard keys being down at the same time

I tried with this code to detect two keyboard arrows being simultaneously pressed:
document.addEventListener('keydown', event => {
if (event.keyCode === 38) {
console.log('up Arrow')
}
if (event.keyCode === 39) {
console.log('right Arrow')
}
})
But it doesn't work, however hard I try to press them at exactly the same time.
How can I cleanly fix this and detect when both keys are down ?
There's only one keyCode per event. You have to track the keys going down, and up:
// if you keep both up and down keys down, you'll get a message
let downKeys = {}; // the set of keys currently down
document.addEventListener('keydown', event => {
downKeys[event.keyCode] = true;
if (downKeys[38] && downKeys[40]) {
console.log("both down!");
}
});
document.addEventListener('keyup', event => {
downKeys[event.keyCode] = false;
});
(you have to go full page to test this snippet)
Here I use 2 flags to check if you are holding the keys.
If both flags are true then it means that you are holding both keys. So, you can perform anything inside the condition.
let holdKeyUp = false;
let holdKeyRight = false;
document.addEventListener('keydown', event => {
if (event.keyCode === 38) {
holdKeyUp = true;
}
if (event.keyCode === 39) {
holdKeyRight = true;
}
if (holdKeyUp && holdKeyRight) {
console.log("Both keys are pressed.");
}
})
document.addEventListener('keyup', event => {
if (event.keyCode === 38) {
holdKeyUp = false;
}
if (event.keyCode === 39) {
holdKeyRight = false;
}
})

Datatable search result add to cart enter key

I have joined a script called jquery.mycart with datatable.
document.onkeydown = function(evt) {
evt = evt || window.event;
var isEscape = false;
if ("key" in evt) {
isEscape = (evt.key == "Enter" || evt.key == "Enter");
} else {
isEscape = (evt.keyCode == 13);
}
if (isEscape) {
table.rows( { search:'applied' } ).data().each(function(value, index) {
console.log(value, index);
});
}
};
I have a problem that when we suppose we search for "Antalgina" when we press enter this search is added to the shopping cart. (look at the console).
Full code
https://codepen.io/anon/pen/oaQJNg
Please how could I do it or give me some hint
I hope you can help me.
Working codePen.
You could a simple jQuery event like :
$("document").on('onkeydown', function (e) {
if (e.keyCode !== 13) {
table.rows( { search:'applied' } ).data().each(function(value, index) {
console.log(value, index);
});
});
});

Categories

Resources