Для вступления я хотел бы объяснить, чего я пытаюсь достичь:
Внутри *div#content*
я хотел бы обнаружить keydown
события И получить элемент, для которого обнаружен элемент нажатия клавиши. Например, TAB внутри абзаца «Программирование — это весело». должен вернуть элемент абзаца и нажать клавишу TAB.
//javascript
const buttonEditable = document.getElementById("buttonEditable");
const contentDiv = document.getElementById("content");
const paragraph = document.getElementById('paragraph');
paragraph.addEventListener('keydown',keydown);
function keydown(){
console.info(event.key); // should return TAB
console.info(event.target); //should return paragraph element
}
buttonEditable.addEventListener('click',toggleEditable);
function toggleEditable(){
if (contentDiv.contentEditable === 'false'){
contentDiv.contentEditable = true;
} else {
contentDiv.contentEditable = false;
};
}
<!-- HTML -->
<div id = "content"> <!-- div container keeps HTML element which are toggled from editable to non-editable-->
<p id = "paragraph">Coding is fun.</p>
<!-- ...bunch of further html element-->
</div>
<button id = "buttonEditable">toggleEditable</button>
Я провел следующее исследование: события «keydown» обнаруживаются только для элементов, имеющих атрибут contenteditable = true
. Кстати, события «щелчка» обнаруживаются независимо от того, установлен ли атрибут contentEditable
.
Добавив contenteditable = true
в html-код. Это работает... Обнаружено нажатие клавиши TAB внутри абзаца:
<div id = "content">
<p id = "paragraph" contenteditable = "true">Coding is fun.</p> <!-- <<<<<<<<<<-------contenteditable added -->
</div>
<button id = "buttonEditable">toggleEditable</button>
Кто-нибудь знает способ, как элемент AND клавиши TAB можно обнаружить по абзацу, который наследует contenteditable = "true"
?
Конечно, с помощью селектора запросов я мог бы назначить атрибут присваивания contenteditable любому элементу внутри div#content, но мне это кажется не очень элегантным.
Кажется, что как только родительский элемент установлен как редактируемый по содержимому, его дочерние узлы больше не могут быть обнаружены/нацелены. Целью события всегда будет самый верхний элемент-узел с редактируемым контентом (почти как и все остальное теперь просто рассматривается как единый общий текстовый контент).
... прецедент ...
function handleKeydown(evt) {
console.info(evt.key);
console.info(evt.target);
}
function toggleTopMostContenteditable () {
const elm = document.querySelector('#content');
elm.contentEditable = (elm.contentEditable !== 'true');
}
document
.querySelectorAll('#content, #content > p')
.forEach(elm =>
elm.addEventListener('keydown', handleKeydown)
);
document
.querySelector('button')
.addEventListener('click', toggleTopMostContenteditable);
body { margin: 0;}
p { margin: 5px; }
#content {
width: 30.7%;
margin: 0 0 10px 0;
padding: 5px;
border: 1px dashed red;
&[contenteditable = "true"],
[contenteditable = "true"] {
border: 1px solid green;
}
}
.as-console-wrapper {
left: auto!important;
bottom: 0;
width: 67%;
min-height: 100%;
}
<div id = "content" contenteditable = "true">
<p contenteditable = "true">Coding is fun.</p>
<p contenteditable = "true">The quick brown fox ...</p>
<p contenteditable = "true">... jumps over the lazy dog.</p>
</div>
<button>Toggle top-most contenteditable</button>
Чтобы достичь того, чего хочет OP, необходимо подделать состояние contentEditable
родительского элемента вместе с реализацией, которая обрабатывает состояния contentEditable
, специфичные для дочернего элемента.
Тоже что-то похожее...
function handleTargetSpecificKeydown(evt) {
console.info(evt.key); // - should return TAB
console.info(evt.target); // - should return paragraph element
}
function handleTargetSpecificEditableState({ target }) {
if (!target.matches('#content')) {
const recentlyEditable = target.contentEditable === 'true';
const currentlyEditable =
(target.closest('#content').dataset.contenteditable === 'true');
if (!recentlyEditable && currentlyEditable) {
target.addEventListener('keydown', handleTargetSpecificKeydown);
target.contentEditable = true;
target.focus();
} else if (recentlyEditable && !currentlyEditable) {
target.contentEditable = false;
target.removeEventListener('keydown', handleTargetSpecificKeydown);
}
}
console.info({
target,
'target.contentEditable': target.contentEditable,
});
}
function toggleOverallEditableState () {
const { dataset } = contentDiv;
dataset.contenteditable = (dataset.contenteditable !== 'true');
console.info({ contentDiv });
}
const contentDiv = document.querySelector('#content');
contentDiv
.addEventListener('click', handleTargetSpecificEditableState);
document
.querySelector('button')
.addEventListener('click', toggleOverallEditableState);
body { margin: 0;}
p { margin: 5px; }
#content {
width: 30.7%;
margin: 0 0 10px 0;
padding: 5px;
p {
border: 1px dashed red;
}
border: 1px dashed red;
&[data-contenteditable = "true"],
[contenteditable = "true"] {
border: 1px solid green;
}
}
.as-console-wrapper {
left: auto!important;
bottom: 0;
width: 67%;
min-height: 100%;
}
<div id = "content">
<p>Coding is fun.</p>
<p>The quick brown fox ...</p>
<p>... jumps over the lazy dog.</p>
</div>
<button>Toggle overeall editable state</button>