Added keyboard events to search modal

This commit is contained in:
squidfunk 2017-03-23 22:41:08 +01:00 committed by Martin Donath
parent 544b1243aa
commit 931465af9f
4 changed files with 84 additions and 48 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -151,7 +151,7 @@
{% endblock %} {% endblock %}
</div> </div>
{% block scripts %} {% block scripts %}
<script src="{{ base_url }}/assets/javascripts/application-269373cb27.js"></script> <script src="{{ base_url }}/assets/javascripts/application-3e4827aebb.js"></script>
<script>app.initialize({url:{base:"{{ base_url }}"}})</script> <script>app.initialize({url:{base:"{{ base_url }}"}})</script>
{% for path in extra_javascript %} {% for path in extra_javascript %}
<script src="{{ path }}"></script> <script src="{{ path }}"></script>

View File

@ -221,61 +221,97 @@ function initialize(config) { // eslint-disable-line func-style
})) }))
/* Listener: keyboard handlers */ /* Listener: keyboard handlers */
new Material.Event.Listener(window, "keyup", ev => { new Material.Event.Listener(window, "keydown", ev => {
switch (ev.key) { const toggle = document.querySelector("[data-md-toggle=search]")
if (!(toggle instanceof HTMLInputElement))
throw new ReferenceError
const query = document.querySelector("[data-md-component=query]")
if (!(query instanceof HTMLInputElement))
throw new ReferenceError
/* Escape: disable search */ /* Search is open */
case "Escape": { if (toggle.checked) {
const toggle = document.querySelector("[data-md-toggle=search]")
if (!(toggle instanceof HTMLInputElement)) /* Escape: close search */
throw new ReferenceError if (ev.key === "Escape") {
if (toggle.checked) { toggle.checked = false
toggle.checked = false toggle.dispatchEvent(new CustomEvent("change"))
toggle.dispatchEvent(new CustomEvent("change")) query.blur()
const query = document.querySelector("[data-md-component=query]")
if (!(query instanceof HTMLInputElement)) /* Horizontal arrows and backspace: focus input */
} else if ([
"ArrowLeft", "ArrowRight", "Backspace"
].indexOf(ev.key) !== -1) {
if (query !== document.activeElement)
query.focus()
/* Vertical arrows and tab: select previous or next search result */
} else if ([
"ArrowUp", "ArrowDown", "Tab"
].indexOf(ev.key) !== -1) {
const key = ev.key === "Tab"
? `Arrow${ev.shiftKey ? "Up" : "Down"}`
: ev.key
/* Retrieve all results */
const links = Array.prototype.slice.call(
document.querySelectorAll("[data-md-component=search] [href]"))
if (!links.length)
return
/* Retrieve current active/focused result */
const focus = links.find(link => {
if (!(link instanceof HTMLElement))
throw new ReferenceError throw new ReferenceError
query.blur() return link.dataset.mdState === "active"
} })
break if (focus)
} focus.dataset.mdState = ""
/* Up arrow: select previous search result */ /* Calculate index depending on direction, add length to form ring */
case "ArrowUp": { const index = Math.max(0, (
const active = document.querySelector( links.indexOf(focus) + links.length + (key === "ArrowUp" ? -1 : +1)
"[data-md-component=search] [href][data-md-state=active]") ) % links.length)
const links = Array.prototype.slice.call(
document.querySelectorAll("[data-md-component=search] [href]")) /* Set active state and focus */
let index = active if (!(links[index] instanceof HTMLElement))
? (links.indexOf(active) - 1) % links.length throw new ReferenceError
: 0
if (index === -1)
index += links.length
if (active)
active.dataset.mdState = ""
links[index].dataset.mdState = "active" links[index].dataset.mdState = "active"
links[index].focus() links[index].focus()
break
/* Prevent scrolling of page */
ev.preventDefault()
ev.stopPropagation()
/* Return false prevents the cursor position from changing */
return false
} }
/* Down arrow: select next search result */ /* Search is closed */
case "ArrowDown": { } else {
const active = document.querySelector(
"[data-md-component=search] [href][data-md-state=active]") // TODO: remove active on mouseover (debounce!) /* S: Open search if not in input field */
const links = Array.prototype.slice.call( if (ev.key === "s") {
document.querySelectorAll("[data-md-component=search] [href]")) query.focus()
const index = active ev.preventDefault()
? (links.indexOf(active) + 1) % links.length
: 0
if (active)
active.dataset.mdState = ""
links[index].dataset.mdState = "active"
links[index].focus()
break
} }
} }
}).listen() }).listen()
/* Listener: focus query if in search is open and character is typed */
new Material.Event.Listener(window, "keypress", () => {
const toggle = document.querySelector("[data-md-toggle=search]")
if (!(toggle instanceof HTMLInputElement))
throw new ReferenceError
if (toggle.checked) {
const query = document.querySelector("[data-md-component=query]")
if (!(query instanceof HTMLInputElement))
throw new ReferenceError
if (query !== document.activeElement)
query.focus()
}
}).listen()
/* Listener: fix unclickable toggle due to blur handler */ /* Listener: fix unclickable toggle due to blur handler */
new Material.Event.MatchMedia("(min-width: 960px)", new Material.Event.MatchMedia("(min-width: 960px)",
new Material.Event.Listener("[data-md-toggle=search]", "click", new Material.Event.Listener("[data-md-toggle=search]", "click",