rowt/frontend/main.ts

460 lines
15 KiB
TypeScript
Raw Normal View History

2023-09-23 21:05:08 +02:00
import Choices from "choices.js";
2023-04-06 13:15:40 +02:00
import { Sidebar } from './js/sidebar';
import './scss/app.scss'
2023-09-23 21:05:08 +02:00
export interface choiceMap {
[details: string]: Choices;
}
let choiceObjects: choiceMap = {};
document.addEventListener('DOMContentLoaded', function() {
initSearch();
2023-04-06 13:15:40 +02:00
initSidebar();
2023-04-07 12:37:33 +02:00
initToggle();
replaceStrings();
2023-09-23 21:05:08 +02:00
initChoices();
initBoatActions();
2023-09-23 21:51:00 +02:00
selectBoatChange();
2023-09-23 22:31:19 +02:00
addRelationMagic(<HTMLElement>document.querySelector('body'));
2023-09-27 13:58:22 +02:00
reloadPage();
2023-09-27 14:46:34 +02:00
setCurrentdate(<HTMLInputElement>document.querySelector('#departure'));
});
2023-09-27 14:46:34 +02:00
function setCurrentdate(input: HTMLInputElement) {
if(input) {
2023-09-28 12:29:44 +02:00
input.value = (new Date().toJSON().slice(0,16));
2023-09-27 14:46:34 +02:00
}
}
2023-09-23 21:51:00 +02:00
function selectBoatChange() {
2023-09-24 10:32:38 +02:00
const boatSelect = <HTMLSelectElement>document.querySelector('#boat_id');
2023-09-27 13:52:15 +02:00
if(boatSelect) {
const boatChoice = new Choices(boatSelect, {
loadingText: 'Wird geladen...',
noResultsText: 'Keine Ergebnisse gefunden',
noChoicesText: 'Keine Ergebnisse gefunden',
itemSelectText: 'Zum Auswählen klicken',
callbackOnCreateTemplates: function () {
return {
option: ({ label, value, customProperties, active, disabled, }: any) => {
const opt: HTMLOptionElement = Choices.defaults.templates.option.call(
this,
{ label, value, customProperties, active, disabled }
);
// We get the original <option> from choicejs
const originalOption: HTMLOptionElement = this._presetOptions.filter(
(option: HTMLOptionElement) => option.value === value
)[0];
const rowers = Number(originalOption.dataset.amount_seats) - 1;
2023-09-28 16:07:52 +02:00
const isShipmasterSteering = originalOption.dataset.default_shipmaster_only_steering;
setMaxAmountRowers(rowers,isShipmasterSteering);
2023-09-27 13:52:15 +02:00
return opt;
}
}
2023-09-24 10:32:38 +02:00
}
2023-09-27 13:52:15 +02:00
} as any);
choiceObjects[boatSelect.id] = boatChoice;
}
2023-09-24 10:32:38 +02:00
const shipmasterSelect = <HTMLSelectElement>document.querySelector('#shipmaster');
2023-09-27 13:52:15 +02:00
if(shipmasterSelect) {
const shipmasterChoice = new Choices(shipmasterSelect, {
loadingText: 'Wird geladen...',
noResultsText: 'Keine Ergebnisse gefunden',
noChoicesText: 'Keine Ergebnisse gefunden',
itemSelectText: 'Zum Auswählen klicken',
});
choiceObjects[shipmasterSelect.id] = shipmasterChoice;
}
2023-09-23 21:51:00 +02:00
}
2023-09-27 13:58:22 +02:00
function reloadPage() {
let pageTitle = document.title;
let attentionMessage = 'Riemen- und Dollenbruch';
document.addEventListener('visibilitychange', function() {
let isPageActive = !document.hidden;
if(!isPageActive){
document.title = attentionMessage;
2023-09-27 14:46:34 +02:00
} else {
2023-09-27 13:58:22 +02:00
document.title = pageTitle;
location.reload();
}
});
}
2023-09-28 16:07:52 +02:00
function setMaxAmountRowers(rowers: number, isShipmasterSteering='false') {
2023-09-28 17:31:20 +02:00
if(choiceObjects['newrower']) {
let curSelection = choiceObjects['newrower'].getValue(true);
2023-09-28 16:18:47 +02:00
let amount_to_delete = (<any>curSelection).length - rowers;
if (amount_to_delete > 0){
let to_delete = (<any>curSelection).slice(-amount_to_delete);
for (let del of to_delete) {
choiceObjects['newrower'].removeActiveItemsByValue(del);
}
}
let input = <HTMLElement>document.querySelector('#newrower');
if(input) {
choiceObjects['newrower'].config.maxItemCount = rowers;
if (rowers === 0) {
choiceObjects['newrower'].disable()
input.parentElement?.parentElement?.parentElement?.classList.add('hidden');
input.parentElement?.parentElement?.parentElement?.classList.add('md:block');
input.parentElement?.parentElement?.parentElement?.classList.add('opacity-50');
} else{
choiceObjects['newrower'].enable();
input.parentElement?.parentElement?.parentElement?.classList.remove('hidden');
input.parentElement?.parentElement?.parentElement?.classList.remove('md:block');
input.parentElement?.parentElement?.parentElement?.classList.remove('opacity-50');
}
}
2023-09-28 16:07:52 +02:00
let only_steering = <HTMLSelectElement>document.querySelector('#shipmaster_only_steering');
if(only_steering) {
if(isShipmasterSteering == 'true') {
only_steering.removeAttribute('disabled');
only_steering.setAttribute('checked', 'true');
2023-09-28 16:18:47 +02:00
only_steering.parentElement?.parentElement?.parentElement?.classList.remove('hidden');
only_steering.parentElement?.parentElement?.parentElement?.classList.remove('md:block');
2023-09-28 16:07:52 +02:00
only_steering.parentElement?.parentElement?.parentElement?.classList.remove('opacity-50');
} else {
only_steering.setAttribute('disabled', 'disabled');
only_steering.removeAttribute('checked');
2023-09-28 16:18:47 +02:00
only_steering.parentElement?.parentElement?.parentElement?.classList.add('hidden');
only_steering.parentElement?.parentElement?.parentElement?.classList.add('md:block');
only_steering.parentElement?.parentElement?.parentElement?.classList.add('opacity-50');
2023-09-28 16:07:52 +02:00
}
}
2023-09-28 17:31:20 +02:00
}
}
2023-09-23 21:05:08 +02:00
function initBoatActions() {
const boatSelects = document.querySelectorAll('.boats-js[data-onclick="true"]');
if(boatSelects) {
Array.prototype.forEach.call(boatSelects, (select: HTMLInputElement) => {
select.addEventListener('click', function() {
if(select.dataset.seats) {
const rowers = Number(select.dataset.seats) - 1;
2023-09-28 16:07:52 +02:00
const isShipmasterSteering = select.dataset.default_shipmaster_only_steering;
2023-09-28 16:07:52 +02:00
setMaxAmountRowers(rowers, isShipmasterSteering);
if (select.dataset.id) {
choiceObjects['boat_id'].setChoiceByValue(select.dataset.id);
}
2023-09-28 16:07:52 +02:00
window.scrollTo(0, 0);
2023-09-28 16:07:52 +02:00
const inputElement = document.getElementById("departure") as HTMLInputElement;
const now = new Date();
const formattedDateTime = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}T${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;
inputElement.value = formattedDateTime;
2023-09-23 21:05:08 +02:00
}
});
});
}
}
function initChoices() {
const selects = document.querySelectorAll('select[data-init="true"]');
if(selects) {
Array.prototype.forEach.call(selects, (select: HTMLInputElement) => {
initNewChoice(select);
});
}
}
function initNewChoice(select: HTMLInputElement) {
const choice = new Choices(select, {
removeItemButton: true,
loadingText: 'Wird geladen...',
noResultsText: 'Keine Ergebnisse gefunden',
noChoicesText: 'Keine Ergebnisse gefunden',
itemSelectText: 'Zum Auswählen klicken',
placeholderValue: 'Ruderer auswählen',
maxItemCount: -1, //TODO
2023-09-23 21:05:08 +02:00
maxItemText: (maxItemCount) => {
return `Nur ${maxItemCount} Ruderer können hinzugefügt werden`;
},
});
choiceObjects[select.id] = choice;
}
2023-04-07 12:37:33 +02:00
function initToggle() {
2023-04-10 22:42:00 +02:00
// get filter btns & set object sessionStorage
const btns = <NodeListOf<HTMLButtonElement>>document.querySelectorAll('.filter-trips-js');
let filterObject = new Map();
2023-04-07 12:37:33 +02:00
2023-04-10 22:42:00 +02:00
if(btns) {
Array.prototype.forEach.call(btns, (btn: HTMLButtonElement) => {
filterObject.set(btn.dataset.action, btn.ariaPressed);
btn.addEventListener('click', () => {
let filter = sessionStorage.getItem('tripsFilter');
if(filter) {
let filterMap = new Map(JSON.parse(filter));
for (let entry of filterMap.entries()) {
2023-04-10 22:46:35 +02:00
if(entry[0] === btn.dataset.action && entry[1] !== 'true') {
2023-04-10 22:42:00 +02:00
filterMap.set(entry[0],'true');
} else {
filterMap.set(entry[0],'false');
}
}
sessionStorage.setItem('tripsFilter', JSON.stringify( Array.from(filterMap.entries())));
}
resetFilteredElements();
2023-04-11 08:27:58 +02:00
if(btn.getAttribute('aria-pressed') === 'false'){
2023-04-10 22:42:00 +02:00
Array.prototype.forEach.call(btns, (b: HTMLButtonElement) => {
b.setAttribute('aria-pressed', 'false');
});
triggerFilterAction(btn.dataset.action);
2023-04-10 22:46:35 +02:00
} else {
btn.setAttribute('aria-pressed', 'false');
2023-04-10 22:42:00 +02:00
}
2023-04-07 12:37:33 +02:00
});
2023-04-10 22:42:00 +02:00
});
}
let filter = sessionStorage.getItem('tripsFilter');
if(filter) {
let filterMap = new Map(JSON.parse(filter));
for (let entry of filterMap.entries()) {
if(entry[1] === 'true') {
triggerFilterAction(entry[0]);
}
}
} else {
sessionStorage.setItem('tripsFilter', JSON.stringify( Array.from(filterObject.entries())));
}
}
function resetFilteredElements() {
const hiddenElements = document.querySelectorAll('.reset-js.hidden');
if(hiddenElements) {
Array.prototype.forEach.call(hiddenElements, (hiddenElement: HTMLButtonElement) => {
hiddenElement.classList.remove('hidden');
2023-04-07 12:37:33 +02:00
});
}
2023-04-10 22:42:00 +02:00
}
2023-04-07 12:37:33 +02:00
2023-04-10 22:42:00 +02:00
function triggerFilterAction(activeFilter: any) {
const activeBtn = document.querySelector('button[data-action="' + activeFilter + '"]');
if(activeBtn) {
activeBtn.setAttribute('aria-pressed', 'true');
2023-04-07 12:37:33 +02:00
2023-04-10 22:42:00 +02:00
filterAction(activeFilter);
}
}
2023-04-07 12:37:33 +02:00
2023-04-10 22:42:00 +02:00
function filterAction(activeFilter: string) {
switch(activeFilter) {
case 'filter-days': {
filterDays();
break;
}
case 'filter-coxs': {
filterCoxs();
break;
}
case 'filter-months': {
filterMonths(activeFilter)
break;
}
2023-04-07 12:37:33 +02:00
}
2023-04-10 22:42:00 +02:00
}
2023-04-10 22:42:00 +02:00
function filterDays() {
const daysNoTrips = document.querySelectorAll('div[data-trips="0"]');
Array.prototype.forEach.call(daysNoTrips, (day: HTMLElement) => {
day.classList.toggle('hidden');
});
}
2023-04-10 22:42:00 +02:00
function filterCoxs() {
const noCoxNeeded = document.querySelectorAll('div[data-coxneeded="false"]');
Array.prototype.forEach.call(noCoxNeeded, (notNeeded: HTMLElement) => {
notNeeded.classList.toggle('hidden');
});
}
function filterMonths(action: string) {
const months = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'];
const monthToggle = <HTMLButtonElement>document.querySelector('button[data-action="' + action + '"]');
if(monthToggle) {
const currentMonth = monthToggle.dataset.month;
if(currentMonth) {
const index = months.indexOf(currentMonth);
if (index > -1) { // only splice array when item is found
months.splice(index, 1); // 2nd parameter means remove one item only
}
Array.prototype.forEach.call(months, (month: HTMLElement) => {
const notThisMonth = document.querySelectorAll('div[data-month="' + month + '"]');
Array.prototype.forEach.call(notThisMonth, (notThisMonth: HTMLElement) => {
notThisMonth.classList.toggle('hidden');
});
});
}
2023-04-10 22:42:00 +02:00
}
}
2023-04-07 12:37:33 +02:00
function initSearch() {
const input = <HTMLInputElement>document.querySelector('#filter-js');
if(input) {
filterElements(input.value);
input.addEventListener('input', () => {
filterElements(input.value);
});
}
}
function filterElements(input: string) {
2023-09-27 15:36:07 +02:00
const elements = document.querySelectorAll('div[data-filterable="true"]');
let resultWrapper = <HTMLElement>document.querySelector('#filter-result-js'),
amountShownElements = 0;
Array.prototype.forEach.call(elements, (element: HTMLElement) => {
// set both strings (input & dataset filter) to lowercase to not be case sensitive
let filterString = element.dataset.filter?.toLocaleLowerCase();
// bulk hide all elements
element.style.display = 'none';
// show if input matches
if(filterString?.includes(input.toLocaleLowerCase())) {
element.style.display = 'flex';
amountShownElements ++;
}
});
if(resultWrapper) {
resultWrapper.innerHTML = (amountShownElements === 0 ? 'Kein Ergebnis gefunden' : '<strong>' + amountShownElements + '</strong>' + (amountShownElements > 1 ? ' Ergebnisse' : ' Ergebnis') + ' gefunden');
}
}
2023-04-06 13:15:40 +02:00
function initSidebar() {
const sidebarTrigger = <NodeListOf<HTMLElement>>document.querySelectorAll('[data-trigger]');
if(sidebarTrigger) {
Array.prototype.forEach.call(sidebarTrigger, (triggerElement: HTMLElement) => {
if(triggerElement.dataset.trigger) {
const sidebar = new Sidebar(triggerElement.dataset.trigger);
triggerElement.addEventListener('click', (e) => {
e.preventDefault();
2023-04-08 09:14:48 +02:00
if(triggerElement.dataset.trigger === 'sidebar') {
initTripSidebar(triggerElement);
}
2023-04-06 13:15:40 +02:00
sidebar.toggle();
});
}
});
}
}
function initTripSidebar(triggerElement: HTMLElement) {
2023-04-08 09:14:48 +02:00
const sidebarElement = <HTMLElement>document.querySelector('#sidebar');
2023-04-08 09:17:46 +02:00
if(sidebarElement && triggerElement.dataset.body && triggerElement.dataset.header) {
let body = <HTMLElement>document.querySelector(triggerElement.dataset.body);
let bodyElement = <HTMLElement>body.cloneNode(true);
let bodyContainerElement = <HTMLElement>sidebarElement.querySelector('.body-js');
2023-09-23 21:05:08 +02:00
const selects = bodyElement.querySelectorAll('select[multiple]');
if(selects) {
Array.prototype.forEach.call(selects, (select: HTMLInputElement) => {
initNewChoice(select);
});
}
/* Quickfix duplicate ids checkboxes */
const checkboxes = <NodeListOf<HTMLElement>>bodyElement.querySelectorAll('input[type="checkbox"]');
Array.prototype.forEach.call(checkboxes, (checkbox: HTMLElement) => {
if(checkbox) {
checkbox.parentElement?.setAttribute('for', checkbox.id + 'js');
checkbox.id += 'js';
}
});
2023-09-05 23:03:18 +02:00
const prefixedContent = <NodeListOf<HTMLElement>>bodyElement.querySelectorAll('.change-id-js');
Array.prototype.forEach.call(prefixedContent, (content: HTMLElement) => {
if(content) {
content.id += 'js';
if(content.dataset.relation){
content.dataset.relation += 'js';
}
}
});
2023-04-08 09:17:46 +02:00
if(bodyContainerElement) {
bodyContainerElement.innerHTML = '';
bodyContainerElement.append(bodyElement);
2023-09-05 23:03:18 +02:00
addRelationMagic(bodyElement);
}
if(triggerElement.dataset.day) {
2023-04-08 09:17:46 +02:00
let hiddenElement = <HTMLInputElement>bodyElement.querySelector('.day-js');
if(hiddenElement) {
hiddenElement.value = triggerElement.dataset.day;
}
}
let headerElement = sidebarElement.querySelector('.header-js');
if(headerElement) {
headerElement.innerHTML = triggerElement.dataset.header;
}
}
}
2023-09-05 23:03:18 +02:00
function addRelationMagic(bodyElement: HTMLElement) {
const fields = bodyElement.querySelectorAll('.set-distance-js');
2023-09-23 22:31:19 +02:00
2023-09-05 23:03:18 +02:00
if(fields) {
Array.prototype.forEach.call(fields, (field: HTMLInputElement) => {
if(field.dataset.relation){
const relatedField = <HTMLInputElement>bodyElement.querySelector('#' + field.dataset.relation);
if(relatedField) {
field.addEventListener('input', (e) => {
e.preventDefault();
2023-09-23 22:31:19 +02:00
const dataList = <HTMLDataListElement>document.querySelector('#destinations');
2023-09-05 23:03:18 +02:00
if(dataList) {
var option = Array.prototype.find.call(dataList.options, function(option) {
return option.value === field.value;
});
// Get distance
const distance = option.getAttribute('distance');
if(distance) relatedField.value = distance;
}
});
}
}
});
}
}
function replaceStrings() {
const weekdays = document.querySelectorAll('.weekday-js');
Array.prototype.forEach.call(weekdays, (weekday: HTMLElement) => {
weekday.innerHTML = weekday.innerHTML.replace('Freitag', 'Markttag');
});
}