forked from MapComplete/MapComplete
108 lines
3.5 KiB
TypeScript
108 lines
3.5 KiB
TypeScript
import ThemeConfig from "../ThemeConfig/ThemeConfig"
|
|
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
|
import Hotkeys from "../../UI/Base/Hotkeys"
|
|
import Translations from "../../UI/i18n/Translations"
|
|
import ThemeViewState from "../ThemeViewState"
|
|
|
|
export class WithVisualFeedbackState extends ThemeViewState {
|
|
/**
|
|
* If true, the user interface will toggle some extra aids for people using screenreaders and keyboard navigation
|
|
* Triggered by navigating the map with arrows or by pressing 'space' or 'enter'
|
|
*/
|
|
public readonly visualFeedback: UIEventSource<boolean> = new UIEventSource<boolean>(false)
|
|
|
|
constructor(theme: ThemeConfig, mvtAvailableLayers: Store<Set<string>>) {
|
|
super(theme, mvtAvailableLayers)
|
|
this.initHotkeysVisualFeedback()
|
|
|
|
///// ACTORS /////
|
|
|
|
this.userRelatedState.a11y.addCallbackAndRunD((a11y) => {
|
|
if (a11y === "always") {
|
|
this.visualFeedback.setData(true)
|
|
} else if (a11y === "never") {
|
|
this.visualFeedback.setData(false)
|
|
}
|
|
})
|
|
this.mapProperties.onKeyNavigationEvent((keyEvent) => {
|
|
if (this.userRelatedState.a11y.data === "never") {
|
|
return
|
|
}
|
|
if (["north", "east", "south", "west"].indexOf(keyEvent.key) >= 0) {
|
|
this.visualFeedback.setData(true)
|
|
return true // Our job is done, unregister
|
|
}
|
|
})
|
|
}
|
|
|
|
|
|
/**
|
|
* Selects the feature that is 'i' closest to the map center
|
|
*/
|
|
private selectClosestAtCenter(i: number = 0) {
|
|
console.log("Selecting closest", i)
|
|
if (this.userRelatedState.a11y.data !== "never") {
|
|
this.visualFeedback.setData(true)
|
|
}
|
|
|
|
const toSelect = this.closestFeatures.features?.data?.[i]
|
|
if (!toSelect) {
|
|
window.requestAnimationFrame(() => {
|
|
const toSelect = this.closestFeatures.features?.data?.[i]
|
|
if (!toSelect) {
|
|
return
|
|
}
|
|
this.setSelectedElement(toSelect)
|
|
})
|
|
return
|
|
}
|
|
this.setSelectedElement(toSelect)
|
|
}
|
|
|
|
private initHotkeysVisualFeedback() {
|
|
const docs = Translations.t.hotkeyDocumentation
|
|
|
|
Hotkeys.RegisterHotkey(
|
|
{
|
|
nomod: " ",
|
|
onUp: true
|
|
},
|
|
docs.selectItem,
|
|
() => {
|
|
if (this.selectedElement.data !== undefined) {
|
|
return false
|
|
}
|
|
if (this.guistate.isSomethingOpen()) {
|
|
return
|
|
}
|
|
if (
|
|
document.activeElement.tagName === "button" ||
|
|
document.activeElement.tagName === "input"
|
|
) {
|
|
return
|
|
}
|
|
this.selectClosestAtCenter(0)
|
|
}
|
|
)
|
|
|
|
for (let i = 1; i < 9; i++) {
|
|
let doc = docs.selectItemI.Subs({ i })
|
|
if (i === 1) {
|
|
doc = docs.selectItem
|
|
} else if (i === 2) {
|
|
doc = docs.selectItem2
|
|
} else if (i === 3) {
|
|
doc = docs.selectItem3
|
|
}
|
|
Hotkeys.RegisterHotkey(
|
|
{
|
|
nomod: "" + i,
|
|
onUp: true
|
|
},
|
|
doc,
|
|
() => this.selectClosestAtCenter(i - 1)
|
|
)
|
|
}
|
|
|
|
}
|
|
}
|