houdini/client/js/components/address-autocomplete.js

82 lines
2.5 KiB
JavaScript
Raw Normal View History

// License: LGPL-3.0-or-later
const R = require('ramda')
const flyd = require('flyd')
// Stream that has true when google script is loaded
const loaded$ = flyd.stream()
// Stream of autocomplete data
const data$ = flyd.stream()
function initScript() {
// if(document.getElementById('googleAutocomplete')) return
// var script = document.createElement('script')
// script.type = 'text/javascript'
// script.id = 'googleAutocomplete'
// document.body.appendChild(script)
// script.src = `https://maps.googleapis.com/maps/api/js?key=${app.google_api}&libraries=places&callback=initGoogleAutocomplete`
return loaded$
}
window.initGoogleAutocomplete = () => loaded$(true)
function initInput(input) {
var autocomplete = new google.maps.places.Autocomplete(input, {types: ['geocode']})
autocomplete.addListener('place_changed', fillInAddress(autocomplete))
input.addEventListener('focus', geolocate(autocomplete))
input.addEventListener('keydown', e => { if(e.which === 13) e.preventDefault() })
return data$
}
const acceptedTypes = {
street_number: 'short_name'
, route: 'long_name'
, locality: 'long_name'
, administrative_area_level_1: 'short_name'
, country: 'long_name'
, postal_code: 'short_name'
}
const fillInAddress = autocomplete => () => {
var place = { components: autocomplete.getPlace().address_components}
if(!place.components) return
place.types = R.map(x => x.types[0], place.components)
var address = placeData(place, 'street_number')
? placeData(place, 'street_number') + ' ' + placeData(place, 'route')
: ''
var data = {
address: address
, city: placeData(place, 'locality')
, state_code: placeData(place, 'administrative_area_level_1')
, country: placeData(place, 'country')
, zip_code: placeData(place, 'postal_code')
}
data$(data)
}
function placeData(place, key) {
const i = R.findIndex(R.equals(key), place.types)
if(i >= 0) return place.components[i][acceptedTypes[key]]
return ''
}
// Bias the autocomplete object to the user's geographical location,
// as supplied by the browser's 'navigator.geolocation' object.
const geolocate = autocomplete => () => {
if(!navigator || !navigator.geolocation) return
navigator.geolocation.getCurrentPosition(pos => {
var geolocation = {
lat: pos.coords.latitude
, lng: pos.coords.longitude
}
var circle = new google.maps.Circle({
center: geolocation
, radius: pos.coords.accuracy
})
autocomplete.setBounds(circle.getBounds())
})
}
module.exports = {initScript, initInput, data$, loaded$}