2020-01-08 21:36:29 +00:00
|
|
|
const get_locale = (fallback = 'en') => {
|
|
|
|
const urlParams = new URLSearchParams(window.location.search)
|
|
|
|
|
|
|
|
for (const lc of [
|
|
|
|
urlParams.get('hl'),
|
|
|
|
navigator.languages,
|
|
|
|
navigator.language,
|
|
|
|
navigator.browserLanguage,
|
|
|
|
navigator.userLanguage,
|
|
|
|
fallback,
|
|
|
|
]) {
|
|
|
|
if (!lc) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (typeof lc) {
|
|
|
|
case 'object':
|
|
|
|
if (lc.length > 0) {
|
|
|
|
return lc[0].split('-')[0]
|
|
|
|
}
|
|
|
|
break
|
|
|
|
case 'string':
|
|
|
|
return lc.split('-')[0]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return fallback
|
|
|
|
}
|
|
|
|
|
|
|
|
const i18n = new VueI18n({
|
|
|
|
locale: get_locale(),
|
|
|
|
|
|
|
|
messages: {
|
|
|
|
de: {
|
|
|
|
btnModalOK: 'OK',
|
|
|
|
optKeepSending: 'Position kontinuierlich senden',
|
|
|
|
optKeepSendingSub: '(wenn aktiviert, wird die Position gesendet, solange dieses Fenster offen ist)',
|
|
|
|
optRetainLocation: 'Position auf dem Server speichern',
|
|
|
|
optRetainLocationSub: '(neue Beobachter sehen die Position sofort)',
|
|
|
|
btnShareMyLocation: 'Meine Position senden!',
|
|
|
|
shareSettings: 'Einstellungen',
|
|
|
|
waitingForLocation: 'Warte auf Position...',
|
|
|
|
},
|
|
|
|
en: {
|
|
|
|
btnModalOK: 'OK',
|
|
|
|
optKeepSending: 'Keep sending location',
|
|
|
|
optKeepSendingSub: '(when enabled location is updated as long as this window is open)',
|
|
|
|
optRetainLocation: 'Retain location on server',
|
|
|
|
optRetainLocationSub: '(new viewers instantly see your location)',
|
|
|
|
btnShareMyLocation: 'Share my location!',
|
|
|
|
shareSettings: 'Share-Settings',
|
|
|
|
waitingForLocation: 'Waiting for location...',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
2020-01-06 23:29:42 +00:00
|
|
|
window.app = new Vue({
|
2020-01-06 23:19:11 +00:00
|
|
|
|
|
|
|
created() {
|
|
|
|
// Use defaults with custom icon paths
|
|
|
|
this.icon = L.icon({
|
|
|
|
...L.Icon.Default.prototype.options,
|
|
|
|
iconUrl: '/asset/leaflet/marker-icon.png',
|
|
|
|
iconRetinaUrl: '/asset/leaflet/marker-icon-2x.png',
|
|
|
|
shadowUrl: '/asset/leaflet/marker-shadow.png',
|
|
|
|
})
|
|
|
|
|
2020-01-06 23:29:42 +00:00
|
|
|
/*
|
|
|
|
* This is only to detect another user updated the location
|
|
|
|
* therefore this is NOT cryptographically safe!
|
|
|
|
*/
|
2020-01-06 23:19:11 +00:00
|
|
|
this.browserID = localStorage.getItem('browserID')
|
|
|
|
if (!this.browserID) {
|
2020-01-06 23:29:42 +00:00
|
|
|
this.browserID = Math.random().toString(16)
|
|
|
|
.substr(2)
|
2020-01-06 23:19:11 +00:00
|
|
|
localStorage.setItem('browserID', this.browserID)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
data: {
|
|
|
|
browserID: null,
|
|
|
|
icon: null,
|
|
|
|
loc: null,
|
|
|
|
map: null,
|
|
|
|
marker: null,
|
|
|
|
shareActive: false,
|
|
|
|
shareSettings: {
|
|
|
|
continuous: true,
|
|
|
|
retained: false,
|
|
|
|
},
|
|
|
|
shareSettingsOpen: false,
|
|
|
|
socket: null,
|
|
|
|
},
|
|
|
|
|
|
|
|
el: '#app',
|
|
|
|
|
2020-01-08 21:36:29 +00:00
|
|
|
i18n,
|
|
|
|
|
2020-01-06 23:19:11 +00:00
|
|
|
methods: {
|
|
|
|
initMap() {
|
|
|
|
this.map = L.map('map')
|
2020-01-06 23:29:42 +00:00
|
|
|
.setView([0, 0], 13)
|
2020-01-06 23:19:11 +00:00
|
|
|
|
|
|
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
2020-01-06 23:29:42 +00:00
|
|
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
2020-01-06 23:19:11 +00:00
|
|
|
}).addTo(this.map)
|
|
|
|
},
|
|
|
|
|
|
|
|
shareLocation() {
|
|
|
|
this.shareActive = true
|
|
|
|
|
|
|
|
const opts = {
|
|
|
|
enableHighAccuracy: true,
|
|
|
|
timeout: 5000,
|
|
|
|
maximumAge: 0,
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.shareSettings.continuous) {
|
|
|
|
navigator.geolocation.getCurrentPosition(this.updateLocation, err => console.error(err), opts)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
navigator.geolocation.watchPosition(this.updateLocation, err => console.error(err), opts)
|
|
|
|
},
|
|
|
|
|
|
|
|
subscribe() {
|
|
|
|
if (this.socket) {
|
|
|
|
// Dispose old socket
|
|
|
|
this.socket.close()
|
|
|
|
this.socket = null
|
|
|
|
}
|
|
|
|
|
2020-01-08 21:36:29 +00:00
|
|
|
let socketAddr = window.location.href.replace(/^http/, 'ws')
|
|
|
|
socketAddr = socketAddr.split('#')[0]
|
|
|
|
socketAddr = socketAddr.split('?')[0]
|
|
|
|
socketAddr = `${socketAddr}/ws`
|
|
|
|
|
|
|
|
this.socket = new WebSocket(socketAddr)
|
2020-01-06 23:19:11 +00:00
|
|
|
this.socket.onclose = () => window.setTimeout(this.subscribe, 1000) // Restart socket
|
|
|
|
this.socket.onmessage = evt => {
|
2020-01-06 23:29:42 +00:00
|
|
|
const loc = JSON.parse(evt.data)
|
2020-01-06 23:19:11 +00:00
|
|
|
loc.time = new Date(loc.time)
|
2020-01-06 23:29:42 +00:00
|
|
|
this.loc = loc
|
2020-01-06 23:19:11 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
updateLocation(pos) {
|
|
|
|
const data = {
|
|
|
|
lat: pos.coords.latitude,
|
|
|
|
lon: pos.coords.longitude,
|
|
|
|
retained: this.shareSettings.retained,
|
|
|
|
sender_id: this.browserID,
|
|
|
|
}
|
|
|
|
|
|
|
|
return axios.put(window.location.href.split('#')[0], data)
|
|
|
|
.catch(err => console.error(err))
|
|
|
|
},
|
|
|
|
|
|
|
|
updateMap() {
|
|
|
|
const center = [this.loc.lat, this.loc.lon]
|
|
|
|
|
|
|
|
if (!this.marker) {
|
2020-01-06 23:29:42 +00:00
|
|
|
this.marker = L.marker(center, { icon: this.icon })
|
2020-01-06 23:19:11 +00:00
|
|
|
.addTo(this.map)
|
|
|
|
}
|
|
|
|
|
|
|
|
this.map.panTo(center)
|
|
|
|
this.marker.setLatLng(center)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
mounted() {
|
|
|
|
this.initMap()
|
|
|
|
this.subscribe()
|
|
|
|
},
|
|
|
|
|
|
|
|
watch: {
|
|
|
|
loc() {
|
|
|
|
this.updateMap()
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|