dev #160

Merged
sora merged 97 commits from dev into master 2025-03-02 01:09:30 +01:00
Showing only changes of commit 52b3d98fec - Show all commits

View File

@ -16,172 +16,228 @@ Vue.component("multiselect", window.VueMultiselect.default);
Vue.use(window.VueTextareaAutosize); Vue.use(window.VueTextareaAutosize);
const app = new Vue({ const app = new Vue({
el: "#app", el: "#app",
data: { data: {
journey_edit: edit_active: ["view", "short"].indexOf(window.location.pathname.split("/")[1]) == -1,
["view", "short"].indexOf(window.location.pathname.split("/")[1]) == -1, drawer_active: "hotel",
journey: new journey_wrapper(window.location.pathname.split("/").pop() || String.gen_id(16)), journey: new journey_wrapper(window.location.pathname.split("/").pop() || String.gen_id(16)),
map_override: { active: false, center: [0, 0] },
query: { query: {
type: "", type: "", res: [],
act: false, },
res: [], impexp: "",
}, lang: {
impexp: "", format: "ddd D MMM",
lang: { formatLocale: {
format: "ddd D MMM", firstDayOfWeek: 1,
formatLocale: { },
firstDayOfWeek: 1, monthBeforeYear: true,
}, },
monthBeforeYear: true, polyline: {
}, latlngs: [],
polyline: { color: 'green'
latlngs: [], }
color: 'green' },
} methods: {
}, start_journey: function () { window.location.href = "/" + this.journey.id },
methods: {
start_journey: function () { window.location.href = "/" + this.journey.id },
compute_bb: function () { compute_bb: function () {
const bounds = this.$refs.map[0].mapObject.getBounds(); const bounds = this.$refs.map[0].mapObject.getBounds();
return [[bounds.getSouthWest().lng, bounds.getSouthWest().lat], return [[bounds.getSouthWest().lng, bounds.getSouthWest().lat],
[bounds.getNorthEast().lng, bounds.getNorthEast().lat]] [bounds.getNorthEast().lng, bounds.getNorthEast().lat]]
}, },
generate_rotation: function (index, list) { generate_rotation: function (index, list) {
if (index < 0 || index >= list.length) return 0; if (index < 0 || index >= list.length) return 0;
const c0 = list[(index == 0) ? index : (index - 1)] const c0 = list[(index == 0) ? index : (index - 1)]
const c1 = list[(index == list.length - 1) ? index : (index + 1)] const c1 = list[(index == list.length - 1) ? index : (index + 1)]
const brng = Math.atan2(c1[1] - c0[1], c1[0] - c0[0]); const brng = Math.atan2(c1[1] - c0[1], c1[0] - c0[0]);
return `rotate:${brng - Math.PI / 2}rad`; return `rotate:${brng - Math.PI / 2}rad`;
}, },
generate_marker: function (item, fcolor) { generate_marker: function (item, fcolor) {
return ` return `
<div style="position: absolute;top: -30px;left: -6px;"> <div style="position: absolute;top: -30px;left: -6px;">
<i class=" fa fa-${api.icon_type(item) || "star"} fa-lg icon-white" style="position: absolute;text-align:center; width:24px;height:24px; line-height:1.5em"></i> <i class=" fa fa-${api.icon_type(item) || "star"} fa-lg icon-white" style="position: absolute;text-align:center; width:24px;height:24px; line-height:1.5em"></i>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 36" width="24" height="36"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 36" width="24" height="36">
<circle cx="12" cy="12" r="12" fill="${fcolor || item.color || "blue"}"/> <circle cx="12" cy="12" r="12" fill="${fcolor || item.color || "blue"}"/>
<polygon points="4,12 20,12 12,36" fill="${fcolor || item.color || "blue"}" /></svg>` <polygon points="4,12 20,12 12,36" fill="${fcolor || item.color || "blue"}" /></svg>`
}, },
generate_icon: function (item, fcolor, styling = "") { generate_icon: function (item, fcolor, styling = "") {
return `<i class="fa fa-${api.icon_type(item) || "star"} fa-2x" style="${styling}; color:${fcolor}; margin-left:-12px; margin-top:-32px; text-align:center; align-content:center; width:32px; height:32px;"></i>`; return `<i class="fa fa-${api.icon_type(item) || "star"} fa-2x" style="${styling}; color:${fcolor}; margin-left:-12px; margin-top:-32px; text-align:center; align-content:center; width:32px; height:32px;"></i>`;
}, },
import_data: function () { import_data: function () {
this.journey.data = Object.assign( this.journey.data = Object.assign(
{}, {},
JSON.parse(this.impexp.toDecoded()), JSON.parse(this.impexp.toDecoded()),
); );
this.journey.data.main.forEach((e) => { this.journey.data.main.forEach((e) => {
if (e.date_range) { if (e.date_range) {
e.date_range[0] = new Date(e.date_range[0]); e.date_range[0] = new Date(e.date_range[0]);
e.date_range[1] = new Date(e.date_range[1]); e.date_range[1] = new Date(e.date_range[1]);
} }
}); });
}, },
export_data: function () { export_data: function () {
this.impexp = JSON.stringify(this.journey.data).toEncoded(); this.impexp = JSON.stringify(this.journey.data).toEncoded();
}, },
filter_selected: function (list, step) { filter_selected: function (list, step) {
return list.filter((e) => return list.filter((e) =>
step ? e.step == this.journey.sel_day : e.step >= 0, step ? e.step == this.journey.sel_day : e.step >= 0,
); );
}, },
filter_unselected: function (list) { filter_unselected: function (list) {
return list.filter((e) => e.step == undefined || e.step < 0); return list.filter((e) => e.step == undefined || e.step < 0);
}, },
remove_item: function (list, idx) { remove_item: function (list, idx) {
list[idx].step = -1; list[idx].step = -1;
list.splice(idx, 1); list.splice(idx, 1);
}, },
log: function (e) { log: function (e) {
console.log(e); console.log(e);
}, },
get_filter: function (f) { get_filter: function (f) {
switch (f) { switch (f) {
case "hotel": return api.is_hotel_type; case "hotel": return api.is_hotel_type;
case "restaurant": return api.is_restauration_type; case "restaurant": return api.is_restauration_type;
case "place": return api.is_attraction_type; case "place": return api.is_attraction_type;
case "other": case "other":
default: return () => true; default: return () => true;
} }
}, },
search_nominatim: function (f) { search_nominatim: function (f) {
return (q) => { return (q) => {
this.query.act = true; this.query.type = f;
this.query.type = f; return api.query_nominatim(q, this.compute_bb(), this.get_filter(f)).catch((_err) => []).then((r) => {
return api.query_nominatim(q, this.compute_bb(), this.get_filter(f)).catch((_err) => []).then((r) => { r.forEach((rr) => {
r.forEach((rr) => { rr.latlon = [parseFloat(rr.lat), parseFloat(rr.lon)];
rr.latlon = [parseFloat(rr.lat), parseFloat(rr.lon)]; rr.sname = rr.display_name.split(",")[0];
rr.sname = rr.display_name.split(",")[0]; });
}); this.query.res = r;
this.query.res = r; this.query.type = null;
this.query.act = false; return r
return r });
}); }
} },
}, search_travel: function (f) {
search_travel: function (f) { return (q) => {
return (q) => { this.query.type = f;
this.query.act = true; return api.query_flight(q).then((r) => {
this.query.type = f; r.forEach(el => {
return api.query_flight(q).then((r) => { el.path = getGeoLine(
r.forEach(el => el.path = getGeoLine( { lat: el.from_geo.lat, lng: el.from_geo.lon },
new L.LatLng(el.from_geo.lat, el.from_geo.lon), { lat: el.to_geo.lat, lng: el.to_geo.lon }, { dist: 5_000_000 }).map(v => [v.lat, v.lng])
new L.LatLng(el.to_geo.lat, el.to_geo.lon), { dist: 5_000_000 }).map(v => [v.lat, v.lng])); el.type = "flight";
this.query.res = r; });
this.query.act = false; this.query.res = r;
return r; this.query.type = null;
}); return r;
} });
}, }
},
keyboardEvent(e) { drawer_hover_item: function (item) {
if (e.which === 13) { if (item) {
} this.map_override.active = true
}, this.map_override.center = [item.lat, item.lon]
}, } else {
created: function () { this.map_override.active = false
}
},
this.search_hotel = api.throttle(this.search_nominatim("hotel"), 1000) drawer_click_item: function (item) {
this.search_restaurant = api.throttle(this.search_nominatim("restaurant"), 1000) console.log(item)
this.search_place = api.throttle(this.search_nominatim("place"), 1000) console.log(this.journey.leg_get())
this.save_data = api.throttle(() => { switch (this.drawer_active) {
this.impexp = JSON.stringify(this.journey.data).toEncoded(); case 'hotel': return this.journey.leg_get().hotel = item;
api.save(this.journey.id, this.journey.data); case 'restaurant': return this.journey.leg_get().places.restaurants.push(item);
}, 1000); case 'place': return this.journey.leg_get().places.places.push(item);
this.search_flight = api.throttle(this.search_travel("flight"), 2000) case 'other': return;
case 'flight': return this.journey.leg_get().travel.push(item);
}
},
window.addEventListener("keydown", (e) => { search_active: function (q) {
switch (e.key) { const txt = q.target.value
case "ArrowLeft": switch (this.drawer_active) {
this.journey.day_prev(); case 'hotel': return this.search_hotel(txt);
break; case 'restaurant': return this.search_restaurant(txt);
case "ArrowRight": case 'place': return this.search_place(txt);
this.journey.day_next(); case 'other': return this.search_other(txt);
break; case 'flight': return this.search_flight(txt);
default: }
console.log(e.key); },
}
});
api.load(this.journey.id).then((r) => (app.journey.data = migrator(r))); keyboardEvent(e) {
if (e.which === 13) {
}
},
},
created: function () {
this.search_hotel = api.throttle(this.search_nominatim("hotel"), 1000)
this.search_restaurant = api.throttle(this.search_nominatim("restaurant"), 1000)
this.search_place = api.throttle(this.search_nominatim("place"), 1000)
this.save_data = api.throttle(() => {
this.impexp = JSON.stringify(this.journey.data).toEncoded();
api.save(this.journey.id, this.journey.data);
}, 1000);
this.search_flight = api.throttle(this.search_travel("flight"), 2000)
this
this.search_travel("flight")("qf1").then(r => { window.addEventListener("keydown", (e) => {
this.polyline.latlngs = r.map(e => e.path) switch (e.key) {
}); case "ArrowLeft":
this.journey.day_prev();
break;
case "ArrowRight":
this.journey.day_next();
break;
default:
console.log(e.key);
}
});
}, api.load(this.journey.id).then((r) => (app.journey.data = migrator(r)));
watch: {
journey: { // this.search_travel("flight")("qf1").then(r => {
handler: function (ndata, odata) { // // this.polyline.latlngs = r.map(e => e.path)
this.save_data(); // this.journey.data.main[this.journey.sel_leg].travel = r;
}, // });
deep: true,
}, },
}, watch: {
journey: {
handler: function (ndata, odata) {
this.save_data();
},
deep: true,
},
},
}); });
var scrollInterval = null;
var scrollDir = null;
document.querySelector('.scroll-content').addEventListener('mousemove', (e) => {
const c = document.querySelector('.scroll-content')
const newDir =
e.pageX < c.offsetWidth * 0.2 ? 'left' :
(e.pageX > c.offsetWidth * 0.8 ? 'right' : scrollDir)
if (!scrollInterval || scrollDir != newDir) {
if (scrollInterval) clearInterval(scrollInterval)
sideScroll(c, newDir, 25, 10);
}
});
document.querySelector('.scroll-content').addEventListener('mouseleave', () => {
clearInterval(scrollInterval);
scrollInterval = null
});
function sideScroll(element, direction, speed, step) {
scrollDir = direction
scrollInterval = setInterval(() => {
element.scrollLeft += (direction == 'left') ? -step : step;
}, speed);
}