OTM/public/js/main.js

496 lines
14 KiB
JavaScript
Raw Normal View History

2023-07-19 12:29:44 +02:00
const gen_id = (length) => {
var result = "";
const characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
const len = characters.length;
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * len));
}
return result;
};
2021-08-04 14:43:00 +02:00
2023-07-19 12:29:44 +02:00
Date.prototype.toJSONLocal = (function () {
function addZ(n) {
return (n < 10 ? "0" : "") + n;
2023-06-14 15:46:43 +02:00
}
2023-07-19 12:29:44 +02:00
return function () {
return (
this.getFullYear() +
"-" +
addZ(this.getMonth() + 1) +
"-" +
addZ(this.getDate())
2023-06-14 15:46:43 +02:00
);
2023-07-19 12:29:44 +02:00
};
})();
2023-06-14 15:46:43 +02:00
2023-07-19 12:29:44 +02:00
function toEncoded(string) {
const codeUnits = Uint16Array.from(
{ length: string.length },
2023-08-02 08:12:41 +02:00
(element, index) => string.charCodeAt(index),
2023-07-19 12:29:44 +02:00
);
const charCodes = new Uint8Array(codeUnits.buffer);
2023-06-14 15:46:43 +02:00
2023-07-19 12:29:44 +02:00
let result = "";
charCodes.forEach((char) => {
result += String.fromCharCode(char);
});
return window.btoa(result);
}
2021-07-16 09:12:30 +02:00
2023-07-19 12:29:44 +02:00
function toDecoded(string) {
let binary = window.atob(string);
const bytes = Uint8Array.from({ length: binary.length }, (element, index) =>
2023-08-02 08:12:41 +02:00
binary.charCodeAt(index),
2023-07-19 12:29:44 +02:00
);
const charCodes = new Uint16Array(bytes.buffer);
2021-07-16 09:12:30 +02:00
2023-07-19 12:29:44 +02:00
let result = "";
charCodes.forEach((char) => {
result += String.fromCharCode(char);
});
return result;
2021-07-16 09:12:30 +02:00
}
2023-07-19 12:29:44 +02:00
const query_nominatim = (q, f) =>
axios
.get("/api/place/" + q)
.then((res) => res.data)
.then((res) => res.filter(f));
const query_flight = (q) =>
axios.get("/api/flight/" + q).then((res) => res.data);
const is_restauration_type = (e) =>
["restaurant", "cafe", "pub", "bar", "fast_food", "food_court"].indexOf(
2023-08-02 08:12:41 +02:00
e.type,
2023-07-19 12:29:44 +02:00
) != -1;
const is_attraction_type = (e) =>
[
"tourism",
"leisure",
"place",
"amenity",
"highway",
"historic",
"natural",
"waterway",
].indexOf(e.category) != -1 ||
[
"place_of_worship",
"national_park",
"nature_reserve",
"protected_area",
].indexOf(e.type != -1);
const icon_type = (item) => {
let t = item.type;
let c = item.category;
const arr = ["restaurant", "cafe", "pub", "bar", "fast_food", "food_court"];
if (arr.indexOf(t) != -1) {
return "utensils";
} else if (t == "hotel" || t == "hostel") {
return "bed";
} else if (t == "museum" || c == "historic" || t == "place_of_worship") {
return "landmark";
} else if (t == "peak" || t == "viewpoint") {
return "mountain";
} else if (t == "parking") {
return "parking";
} else if (
t == "water" ||
t == "river" ||
t == "lake" ||
t == "torrent" ||
t == "aquarium"
) {
return "water";
} else if (t == "community_centre" || t == "locality") {
return "building";
} else if (t == "attraction") {
return "landmark";
} else if (t == "information" || t == "university") {
return "landmark";
} else if (t == "bridge") {
return "archway";
} else if (
t == "woodland" ||
t == "shieling" ||
t == "national_park" ||
t == "zoo" ||
t == "park" ||
t == "garden" ||
0
) {
return "tree";
} else if ((t == "water_park", t == "theme_park")) {
return "dice-five";
} else if (
t == "?" ||
t == "neighbourhood" ||
t == "quarter" ||
c == "highway"
) {
return "";
} else {
console.log(item.display_name, item.category, item.type);
return "question";
}
};
Vue.component("l-map", window.Vue2Leaflet.LMap);
Vue.component("l-tile-layer", window.Vue2Leaflet.LTileLayer);
Vue.component("l-marker", window.Vue2Leaflet.LMarker);
Vue.component("l-icon", window.Vue2Leaflet.LIcon);
Vue.component("l-popup", window.Vue2Leaflet.LPopup);
Vue.component("l-tooltip", window.Vue2Leaflet.LTooltip);
Vue.component("l-control-scale", window.Vue2Leaflet.LControlScale);
Vue.component("multiselect", window.VueMultiselect.default);
2022-03-23 10:47:49 +01:00
Vue.use(window.VueTextareaAutosize);
2021-07-16 09:12:30 +02:00
2022-03-23 10:35:46 +01:00
const app = new Vue({
2023-07-19 12:29:44 +02:00
el: "#app",
data: {
journey_edit:
["view", "short"].indexOf(window.location.pathname.split("/")[1]) == -1,
journey_id: window.location.pathname.split("/").pop() || gen_id(16),
2021-07-16 16:17:55 +02:00
2023-07-19 12:29:44 +02:00
journey_step_data: { day: 1, section: 0 },
journey_data: {
name: "New Journey",
main: [],
},
2023-06-25 23:10:03 +02:00
2023-07-19 12:29:44 +02:00
query: { hotel: [], flight: [], nominatim: [] },
querying: { hotel: false, flight: false, place: false, food: false },
impexp: "",
lang: {
format: "ddd D MMM",
formatLocale: {
firstDayOfWeek: 1,
},
monthBeforeYear: true,
},
},
methods: {
start_journey: function (event) {
window.location.href = "/" + this.journey_id;
},
add_section: function (event) {
if (this.journey_data.main == undefined) this.journey_data.main = [];
this.journey_data.main.push({
title: "?",
step_title: [],
map: { zoom: 2 },
hotel: { latlon: [0, 0] },
places: { restaurants: [], places: [] },
});
},
step_len: function (idx) {
return this.journey_data.main[idx].dateRange
? (this.journey_data.main[idx].dateRange[1] -
this.journey_data.main[idx].dateRange[0]) /
(1000 * 60 * 60 * 24) +
1
: 1;
},
next_step: function () {
this.journey_step_data.day += 1;
let s = this.journey_step_data.section;
let cd = this.step_len(s);
2023-07-19 09:23:30 +02:00
2023-07-19 12:29:44 +02:00
if (this.journey_step_data.day > cd) {
this.journey_step_data.section += 1;
if (this.journey_step_data.section >= this.journey_data.main.length) {
this.journey_step_data.section = this.journey_data.main.length - 1;
this.journey_step_data.day = cd;
} else {
this.journey_step_data.day = 1;
}
}
},
prev_step: function () {
this.journey_step_data.day -= 1;
if (this.journey_step_data.day <= 0) {
this.journey_step_data.section -= 1;
if (this.journey_step_data.section < 0) {
this.first_step();
} else {
let s = this.journey_step_data.section;
2023-07-15 13:06:51 +02:00
2023-07-19 12:29:44 +02:00
let cd = this.step_len(s);
this.journey_step_data.day = cd;
}
}
},
nextnext_step: function () {
this.journey_step_data.section += 1;
this.journey_step_data.day = 1;
if (this.journey_step_data.section >= this.journey_data.main.length)
this.first_step();
},
prevprev_step: function () {
this.journey_step_data.section -= 1;
this.journey_step_data.day = 1;
if (this.journey_step_data.section < 0) this.first_step();
},
first_step: function () {
this.journey_step_data.section = 0;
this.journey_step_data.day = 1;
},
2023-07-15 13:06:51 +02:00
2023-07-19 12:29:44 +02:00
active_date: function () {
if (this.journey_step_data.day < 0) return "?";
if (!this.journey_data.main[this.journey_step_data.section].dateRange)
return "?";
var date = new Date(
2023-08-02 08:12:41 +02:00
this.journey_data.main[this.journey_step_data.section].dateRange[0],
2023-07-19 12:29:44 +02:00
);
date.setDate(date.getDate() + this.journey_step_data.day - 1);
return this.format_date(date);
},
format_date: function (d) {
return (
["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][d.getDay()] +
" " +
d.getDate() +
" " +
[
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
][d.getMonth()]
);
},
2021-08-03 13:18:25 +02:00
2023-07-19 12:29:44 +02:00
total_days: function () {
if (this.journey_data.main.length == 0) return 0;
try {
return (
(this.journey_data.main[this.journey_data.main.length - 1]
.dateRange[1] -
this.journey_data.main[0].dateRange[0]) /
(1000 * 60 * 60 * 24)
);
} catch {
return "?";
}
},
total_date: function () {
if (this.journey_data.main.length == 0) return "";
try {
return `${this.format_date(
2023-08-02 08:12:41 +02:00
this.journey_data.main[0].dateRange[0],
2023-07-19 12:29:44 +02:00
)} - ${this.format_date(
2023-08-02 08:12:41 +02:00
this.journey_data.main[this.journey_data.main.length - 1]
.dateRange[1],
2023-07-19 12:29:44 +02:00
)}`;
} catch {
return "?";
}
},
update_date: function (idx) {
let dateRange = this.journey_data.main[idx].dateRange;
let start_end = [0, 0];
let step_len = 0;
2021-07-16 09:12:30 +02:00
2023-07-19 12:29:44 +02:00
let last_start = dateRange[0];
for (let i = idx - 1; i >= 0; --i) {
step_len = this.step_len(i) - 1;
if (this.journey_data.main[i].dateRange) {
start_end = [last_start.getDate() - step_len, last_start.getDate()];
} else {
this.journey_data.main[i].dateRange = [new Date(), new Date()];
start_end = [last_start.getDate() - step_len, last_start.getDate()];
}
this.journey_data.main[i].dateRange[0].setTime(last_start.getTime());
this.journey_data.main[i].dateRange[0].setDate(start_end[0]);
this.journey_data.main[i].dateRange[1].setTime(last_start.getTime());
this.journey_data.main[i].dateRange[1].setDate(start_end[1]);
last_start = this.journey_data.main[i].dateRange[0];
}
2023-07-15 13:45:50 +02:00
2023-07-19 12:29:44 +02:00
let last_end = dateRange[1];
for (let i = idx + 1; i < this.journey_data.main.length; ++i) {
step_len = this.step_len(i) - 1;
if (this.journey_data.main[i].dateRange) {
start_end = [last_end.getDate(), last_end.getDate() + step_len];
} else {
this.journey_data.main[i].dateRange = [new Date(), new Date()];
start_end = [last_end.getDate(), last_end.getDate() + step_len];
}
this.journey_data.main[i].dateRange[0].setTime(last_end.getTime());
this.journey_data.main[i].dateRange[0].setDate(start_end[0]);
this.journey_data.main[i].dateRange[1].setTime(last_end.getTime());
this.journey_data.main[i].dateRange[1].setDate(start_end[1]);
last_end = this.journey_data.main[i].dateRange[1];
}
2021-07-16 09:12:30 +02:00
},
2023-07-15 13:45:50 +02:00
2023-07-19 12:29:44 +02:00
rm_section: function (idx) {
this.journey_data.main.splice(idx, 1);
if (this.journey_step_data.section == idx) {
this.prevprev_step();
}
},
sel_section: function (idx) {
this.journey_step_data.section = idx;
this.journey_step_data.day = 1;
},
search_nominatim: function (txt, f) {
if (txt == "") {
this.query.nominatim = [];
return Promise.resolve([]);
}
return query_nominatim(txt, f).then((results) => {
results.forEach((r) => {
r.latlon = [parseFloat(r.lat), parseFloat(r.lon)];
r.sname = r.display_name.split(",")[0];
2023-07-15 13:45:50 +02:00
});
2023-07-19 12:29:44 +02:00
this.query.nominatim = results;
});
},
search_flight: function (txt) {
if (txt == "") return;
this.querying.flight = true;
query_flight(txt.replace(" ", "")).then((results) => {
if (results.results == "") {
this.query.flight = [];
this.querying.flight = false;
return;
}
this.query.flight = results.results;
this.querying.flight = false;
});
},
generate_icon: function (item, fcolor) {
return L.AwesomeMarkers.icon({
icon: icon_type(item) || "star",
prefix: "fa",
markerColor: fcolor || item.color || "blue",
}).createIcon().outerHTML;
},
2023-07-15 13:45:50 +02:00
2023-07-19 12:29:44 +02:00
save_data: function () {
this.impexp = toEncoded(JSON.stringify(this.journey_data));
axios
.post("/api/" + this.journey_id, this.journey_data)
.then((response) => {
console.log("Saved...");
})
.catch((error) => {
console.warn("Error! Could not reach the API.");
2021-07-16 09:12:30 +02:00
});
},
2023-07-19 12:29:44 +02:00
import_data: function () {
this.journey_data = Object.assign({}, JSON.parse(toDecoded(this.impexp)));
this.journey_data.main.forEach((e) => {
if (e.dateRange) {
e.dateRange[0] = new Date(e.dateRange[0]);
e.dateRange[1] = new Date(e.dateRange[1]);
}
});
},
export_data: function () {
this.impexp = toEncoded(JSON.stringify(this.journey_data));
},
filter_selected: function (list, step) {
return list.filter((e) =>
2023-08-02 08:12:41 +02:00
step ? e.step == this.journey_step_data.day : e.step >= 0,
2023-07-19 12:29:44 +02:00
);
},
filter_unselected: function (list) {
return list.filter((e) => e.step == undefined || e.step < 0);
},
remove_item: function (list, idx) {
list[idx].step = -1;
list.splice(idx, 1);
},
log: function (e) {
console.log(e);
2021-07-16 09:12:30 +02:00
},
2022-03-23 10:06:37 +01:00
2023-07-19 12:29:44 +02:00
keyboardEvent(e) {
if (e.which === 13) {
}
},
},
created: function () {
window.addEventListener("keydown", (e) => {
switch (e.key) {
case "ArrowLeft":
this.prev_step();
break;
case "ArrowRight":
this.next_step();
break;
default:
console.log(e.key);
}
});
axios.get("/api/" + this.journey_id).then((response) => {
if (response.data == "") throw "Invalid Journey Data Received";
app.journey_data = response.data;
for (let e of app.journey_data.main) {
if (e.dateRange) {
e.dateRange[0] = new Date(e.dateRange[0]);
e.dateRange[1] = new Date(e.dateRange[1]);
}
e.step_title = e.step_title || [];
}
});
2022-03-23 10:35:46 +01:00
2023-07-19 12:29:44 +02:00
this.debounceSave = _.debounce(this.save_data, 500);
this.debounceSearch = {
hotel: _.debounce((q) => {
this.querying.hotel = true;
this.search_nominatim(
q,
2023-08-02 08:12:41 +02:00
(r) =>
r.type == "hotel" || r.type == "hostel" || r.type == "guest_house",
2023-07-19 12:29:44 +02:00
).then((r) => {
this.querying.hotel = false;
});
}, 500),
restaurants: _.debounce((q) => {
this.querying.food = true;
this.search_nominatim(q, (r) => is_restauration_type(r)).then((r) => {
this.querying.food = false;
});
}, 500),
places: _.debounce((q) => {
this.querying.place = true;
this.search_nominatim(q, (r) => is_attraction_type(r)).then((r) => {
this.querying.place = false;
});
}, 500),
other: _.debounce((q) => {
this.querying.any = true;
this.search_nominatim(q, (r) => true).then((r) => {
this.querying.any = false;
});
}, 500),
flight: _.debounce((q) => this.search_flight(q), 500),
};
},
watch: {
journey_data: {
handler: function (ndata, odata) {
this.debounceSave();
},
deep: true,
},
},
});