widgets: fix map search widget on mobile (#74634) #127

Merged
csechet merged 1 commits from wip/76634-map-search-on-mobile into main 2023-02-20 11:01:52 +01:00
2 changed files with 69 additions and 48 deletions

View File

@ -634,13 +634,27 @@ div.file-button .widget-message {
width: 100%
}
&--input {
width: 100%;
}
&--result-list {
background-image: none;
padding-right: 0.7em;
background: white;
}
&--result-item {
text-wrap: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer;
padding: 6px;
font-size: 1.2em;
white-space: nowrap;
&:hover, &.selected {
color: white;
background-color: #5897fb;
}
}
}

View File

@ -21,6 +21,7 @@ class SearchControl extends L.Control {
this._map = map
this._container = L.DomUtil.create('div', 'leaflet-search')
this._resultLocations = []
this._selectedIndex = -1
this._buttonBar = L.DomUtil.create('div', 'leaflet-bar', this._container)
@ -35,14 +36,15 @@ class SearchControl extends L.Control {
this._control = L.DomUtil.create('div', 'leaflet-search--control', this._container)
this._control.style.visibility = 'collapse'
this._searchInput = L.DomUtil.create('input', '', this._control)
this._searchInput = L.DomUtil.create('input', 'leaflet-search--input', this._control)
this._searchInput.placeholder = this.options.labels.hint
this._feedback = L.DomUtil.create('div', '', this._control)
this._resultList = L.DomUtil.create('select', 'leaflet-search--result-list', this._control)
this._resultList.size = this.options.maxResults
this._resultList.style.visibility = "collapse"
this._resultList = L.DomUtil.create('div', 'leaflet-search--result-list', this._control)
this._resultList.style.visibility = 'collapse'
this._resultList.tabIndex = 0
this._resultList.setAttribute('aria-role', 'list')
L.DomEvent
.on(this._container, 'click', L.DomEvent.stop, this)
@ -52,8 +54,6 @@ class SearchControl extends L.Control {
.on(this._toggleButton, 'click', this._onToggleButtonClick, this)
.on(this._searchInput, 'keydown', this._onSearchInputKeyDown, this)
.on(this._searchInput, 'input', this._onSearchInput, this)
.on(this._resultList, 'change', this._onResultListChange, this)
.on(this._resultList, 'click', this._onResultListClick, this)
.on(this._resultList, 'keydown', this._onResultListKeyDown, this)
return this._container
@ -62,16 +62,16 @@ class SearchControl extends L.Control {
onRemove (map) {
}
_showControl() {
this._container.classList.add("open")
_showControl () {
this._container.classList.add('open')
this._buttonBar.style.visibility = 'collapse'
this._control.style.removeProperty('visibility')
this._initialBounds = this._map.getBounds()
setTimeout(() => this._searchInput.focus(), 50)
}
_hideControl(resetBounds) {
this._container.classList.remove("open")
_hideControl (resetBounds) {
this._container.classList.remove('open')
if (resetBounds) {
this._map.fitBounds(this._initialBounds)
}
@ -79,7 +79,6 @@ class SearchControl extends L.Control {
this._buttonBar.style.removeProperty('visibility')
this._control.style.visibility = 'collapse'
this._toggleButton.focus()
this._resultList.selectedIndex = -1
}
_onControlFocusIn (event) {
@ -92,16 +91,12 @@ class SearchControl extends L.Control {
this._hideTimeout = setTimeout(() => this._hideControl(), 50)
}
_getSelectedLocation() {
let selectedIndex = this._resultList.selectedIndex
if(selectedIndex == -1) {
if(this._resultLocations.length === 0) {
return null
}
selectedIndex = 0
_getSelectedLocation () {
if (this._selectedIndex === -1) {
return null
}
return this._resultLocations[selectedIndex]
return this._resultLocations[this._selectedIndex]
}
_focusLocation (location) {
@ -130,16 +125,27 @@ class SearchControl extends L.Control {
this._showControl()
}
_selectIndex(index) {
this._resultList.selectedIndex = index
const selectedLocation = this._getSelectedLocation()
this._focusLocation(selectedLocation)
this._resultList.focus()
_selectIndex (index) {
for (const resultItem of this._resultList.children) {
resultItem.classList.remove('selected')
}
this._selectedIndex = index
if (index === -1) {
this._map.fitBounds(this._initialBounds)
this._searchInput.focus()
} else {
this._focusLocation(this._resultLocations[index])
const selectedElement = this._resultList.children[index]
selectedElement.classList.add('selected')
this._resultList.focus()
}
}
_onSearchInputKeyDown (event) {
const results = this._resultList.options
if (results.length == 0) {
const results = this._resultLocations
if (results.length === 0) {
return
}
@ -152,7 +158,7 @@ class SearchControl extends L.Control {
}
}
_clearResults() {
_clearResults () {
while (this._resultList.lastElementChild) {
this._resultList.removeChild(this._resultList.lastElementChild)
}
@ -170,27 +176,28 @@ class SearchControl extends L.Control {
this._clearResults()
this._feedback.innerHTML = this.options.labels.searching
this._feedback.classList.remove("error")
this._feedback.classList.remove('error')
$.ajax({
url: this.options.searchUrl,
data: { q: searchString },
success: (data) => {
this._feedback.innerHTML = ""
this._feedback.innerHTML = ''
this._resultLocations = []
var firstResults = data.slice(0, this.options.maxResults)
const firstResults = data.slice(0, this.options.maxResults)
if(firstResults.length == 0) {
if (firstResults.length === 0) {
return
}
this._resultList.style.removeProperty('visibility')
this._resultList.size = Math.max(2, firstResults.length)
for (const result of firstResults) {
const resultItem = L.DomUtil.create('option', 'leaflet-search--result-item', this._resultList)
const resultItem = L.DomUtil.create('div', 'leaflet-search--result-item', this._resultList)
resultItem.innerHTML = result.display_name
resultItem.title = result.display_name
resultItem.setAttribute('aria-role', 'list-item')
L.DomEvent.on(resultItem, 'click', this._onResultItemClick, this)
const bbox = result.boundingbox
@ -205,7 +212,7 @@ class SearchControl extends L.Control {
},
error: () => {
this._feedback.innerHTML = this.options.labels.error
this._feedback.classList.add("error")
this._feedback.classList.add('error')
}
})
}
@ -219,24 +226,24 @@ class SearchControl extends L.Control {
}
}
_onResultListChange (event) {
const selectedLocation = this._getSelectedLocation()
this._focusLocation(selectedLocation)
}
_onResultListClick (event) {
_onResultItemClick (event) {
const elementIndex = Array.prototype.indexOf.call(this._resultList.children, event.target)
this._selectIndex(elementIndex)
const selectedLocation = this._getSelectedLocation()
this._validateLocation(selectedLocation)
}
_onResultListKeyDown (event) {
const results = this._resultList.options
if (
(event.keyCode === 38 && this._resultList.selectedIndex === 0) ||
(event.keyCode === 40 && this._resultList.selectedIndex === results.length - 1)
) {
this._searchInput.focus()
this._resultList.selectedIndex = -1
const results = this._resultLocations
if (event.keyCode === 38) {
this._selectIndex(this._selectedIndex - 1)
event.preventDefault()
} else if (event.keyCode === 40) {
if (this._selectedIndex === results.length - 1) {
this._selectIndex(-1)
} else {
this._selectIndex(this._selectedIndex + 1)
}
event.preventDefault()
}
}