Merge pull request #3087 from ehuss/limit-global-keypress
Fix global keypresses triggering when other elements are in focus
This commit is contained in:
commit
9190b5d093
12 changed files with 129 additions and 5 deletions
|
|
@ -19,6 +19,17 @@ function playground_text(playground, hidden = true) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for global keypress handlers so they don't trigger when certain elements are active.
|
||||||
|
* @returns {boolean} True if the keypress handler should be skipped.
|
||||||
|
*/
|
||||||
|
function mdbook_something_else_has_focus(e) {
|
||||||
|
// Check composedPath in case the event happened from something generated
|
||||||
|
// from the shadowDOM.
|
||||||
|
const target = e.composedPath()[0] || e.target;
|
||||||
|
return /^(?:input|select|textarea)$/i.test(target.nodeName);
|
||||||
|
}
|
||||||
|
|
||||||
(function codeSnippets() {
|
(function codeSnippets() {
|
||||||
function fetch_with_timeout(url, options, timeout = 6000) {
|
function fetch_with_timeout(url, options, timeout = 6000) {
|
||||||
return Promise.race([
|
return Promise.race([
|
||||||
|
|
@ -648,12 +659,15 @@ aria-label="Show hidden lines"></button>';
|
||||||
|
|
||||||
(function chapterNavigation() {
|
(function chapterNavigation() {
|
||||||
document.addEventListener('keydown', function(e) {
|
document.addEventListener('keydown', function(e) {
|
||||||
if (e.altKey || e.ctrlKey || e.metaKey) {
|
if (e.altKey ||
|
||||||
return;
|
e.ctrlKey ||
|
||||||
}
|
e.metaKey ||
|
||||||
if (window.search && window.search.hasFocus()) {
|
window.search && window.search.hasFocus() ||
|
||||||
|
mdbook_something_else_has_focus(e)
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const html = document.querySelector('html');
|
const html = document.querySelector('html');
|
||||||
|
|
||||||
function next() {
|
function next() {
|
||||||
|
|
|
||||||
|
|
@ -357,7 +357,7 @@ window.search = window.search || {};
|
||||||
e.shiftKey ||
|
e.shiftKey ||
|
||||||
e.target.type === 'textarea' ||
|
e.target.type === 'textarea' ||
|
||||||
e.target.type === 'text' ||
|
e.target.type === 'text' ||
|
||||||
!hasFocus() && /^(?:input|select|textarea)$/i.test(e.target.nodeName)
|
!hasFocus() && mdbook_something_else_has_focus(e)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
tests/gui/books/editor/book.toml
Normal file
6
tests/gui/books/editor/book.toml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
[book]
|
||||||
|
title = "editor"
|
||||||
|
language = "en"
|
||||||
|
|
||||||
|
[output.html.playground]
|
||||||
|
editable = true
|
||||||
4
tests/gui/books/editor/src/SUMMARY.md
Normal file
4
tests/gui/books/editor/src/SUMMARY.md
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
- [Chapter 1](./chapter_1.md)
|
||||||
|
- [Chapter 2](./chapter_2.md)
|
||||||
7
tests/gui/books/editor/src/chapter_1.md
Normal file
7
tests/gui/books/editor/src/chapter_1.md
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Chapter 1
|
||||||
|
|
||||||
|
```rust,editable
|
||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
||||||
|
```
|
||||||
1
tests/gui/books/editor/src/chapter_2.md
Normal file
1
tests/gui/books/editor/src/chapter_2.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
# Chapter 2
|
||||||
6
tests/gui/books/shadow-dom/book.toml
Normal file
6
tests/gui/books/shadow-dom/book.toml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
[book]
|
||||||
|
title = "shadow-dom"
|
||||||
|
language = "en"
|
||||||
|
|
||||||
|
[output.html]
|
||||||
|
additional-js = ["shadow-dom.js"]
|
||||||
38
tests/gui/books/shadow-dom/shadow-dom.js
Normal file
38
tests/gui/books/shadow-dom/shadow-dom.js
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
(function() {
|
||||||
|
let shadowHost = null;
|
||||||
|
let shadowInput = null;
|
||||||
|
|
||||||
|
document.addEventListener('keypress', function(e) {
|
||||||
|
if (e.key === 'x' || e.key === 'X') {
|
||||||
|
if (shadowHost && shadowHost.isConnected) {
|
||||||
|
shadowInput.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowHost = document.createElement('div');
|
||||||
|
shadowHost.id = 'shadow-input-host';
|
||||||
|
shadowHost.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:9999;';
|
||||||
|
|
||||||
|
document.body.appendChild(shadowHost);
|
||||||
|
|
||||||
|
const shadowRoot = shadowHost.attachShadow({ mode: 'open' });
|
||||||
|
|
||||||
|
shadowInput = document.createElement('input');
|
||||||
|
shadowInput.type = 'text';
|
||||||
|
shadowInput.id = 'shadow-input';
|
||||||
|
shadowInput.placeholder = 'Shadow DOM input (press Escape to close)';
|
||||||
|
shadowInput.style.cssText = 'font-size:1.2em;padding:8px;width:300px;';
|
||||||
|
|
||||||
|
shadowRoot.appendChild(shadowInput);
|
||||||
|
shadowInput.focus();
|
||||||
|
|
||||||
|
shadowInput.addEventListener('keydown', function(e) {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
shadowHost.remove();
|
||||||
|
shadowHost = null;
|
||||||
|
shadowInput = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
3
tests/gui/books/shadow-dom/src/SUMMARY.md
Normal file
3
tests/gui/books/shadow-dom/src/SUMMARY.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
- [Chapter 1](./chapter_1.md)
|
||||||
1
tests/gui/books/shadow-dom/src/chapter_1.md
Normal file
1
tests/gui/books/shadow-dom/src/chapter_1.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
# Chapter 1
|
||||||
24
tests/gui/editor-keypress.goml
Normal file
24
tests/gui/editor-keypress.goml
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Tests for global keypress handlers when ACE editor is in focus.
|
||||||
|
// See https://github.com/rust-lang/mdBook/issues/3064
|
||||||
|
|
||||||
|
go-to: |DOC_PATH| + "editor/chapter_1.html"
|
||||||
|
|
||||||
|
click: ".ace_editor"
|
||||||
|
press-key: "s"
|
||||||
|
// Wait briefly to allow any event handlers triggered by the keypress to run.
|
||||||
|
// Otherwise there is a race here since the wrapper is already display:none.
|
||||||
|
wait-for: 200
|
||||||
|
wait-for-css: ("#mdbook-search-wrapper", {"display": "none"})
|
||||||
|
|
||||||
|
// ? inside ACE editor shouldn't show global help popup.
|
||||||
|
press-key: "?"
|
||||||
|
wait-for: 200
|
||||||
|
wait-for-css: ("#mdbook-help-container", {"display": "none"})
|
||||||
|
|
||||||
|
// Make sure arrow keys don"t navigate.
|
||||||
|
press-key: "ArrowRight"
|
||||||
|
wait-for: 200
|
||||||
|
assert-window-property: ({"location": |DOC_PATH| + "editor/chapter_1.html"})
|
||||||
|
press-key: "ArrowLeft"
|
||||||
|
wait-for: 200
|
||||||
|
assert-window-property: ({"location": |DOC_PATH| + "editor/chapter_1.html"})
|
||||||
20
tests/gui/shadow-dom.goml
Normal file
20
tests/gui/shadow-dom.goml
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
// Tests the keypress handler when there is a shadow-dom element.
|
||||||
|
// See https://github.com/rust-lang/mdBook/issues/2507
|
||||||
|
|
||||||
|
go-to: |DOC_PATH| + "shadow-dom/chapter_1.html"
|
||||||
|
|
||||||
|
// Open the shadow-dom generated element.
|
||||||
|
press-key: 'x'
|
||||||
|
wait-for: '#shadow-input-host'
|
||||||
|
// See what happens when the s key is pressed.
|
||||||
|
press-key: 's'
|
||||||
|
wait-for: 200
|
||||||
|
wait-for-css: ("#mdbook-search-wrapper", {"display": "none"})
|
||||||
|
|
||||||
|
// Also try the global key handlers.
|
||||||
|
reload:
|
||||||
|
press-key: 'x'
|
||||||
|
wait-for: '#shadow-input-host'
|
||||||
|
press-key: '?'
|
||||||
|
wait-for: 200
|
||||||
|
wait-for-css: ("#mdbook-help-container", {"display": "none"})
|
||||||
Loading…
Add table
Reference in a new issue