import Choices from "choices.js"; import { Sidebar } from './js/sidebar'; import './scss/app.scss' export interface choiceMap { [details: string]: Choices; } let choiceObjects: choiceMap = {}; document.addEventListener('DOMContentLoaded', function() { initSearch(); initSidebar(); initToggle(); replaceStrings(); initChoices(); initBoatActions(); selectBoatChange(); addRelationMagic(<HTMLElement>document.querySelector('body')); reloadPage(); setCurrentdate(<HTMLInputElement>document.querySelector('#departure')); }); function setCurrentdate(input: HTMLInputElement) { if(input) { input.value = (new Date().toJSON().slice(0,16)); } } function selectBoatChange() { const boatSelect = <HTMLSelectElement>document.querySelector('#boat_id'); 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; const isShipmasterSteering = originalOption.dataset.default_shipmaster_only_steering; setMaxAmountRowers(rowers,isShipmasterSteering); return opt; } } } } as any); choiceObjects[boatSelect.id] = boatChoice; } const shipmasterSelect = <HTMLSelectElement>document.querySelector('#shipmaster'); 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; } } function reloadPage() { let pageTitle = document.title; let attentionMessage = 'Riemen- und Dollenbruch'; document.addEventListener('visibilitychange', function() { let isPageActive = !document.hidden; if(!isPageActive){ document.title = attentionMessage; } else { document.title = pageTitle; location.reload(); } }); } function setMaxAmountRowers(rowers: number, isShipmasterSteering='false') { if(choiceObjects['newrower']) { let curSelection = choiceObjects['newrower'].getValue(true); 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'); } } let only_steering = <HTMLSelectElement>document.querySelector('#shipmaster_only_steering'); if(only_steering) { if(isShipmasterSteering == 'true') { only_steering.removeAttribute('disabled'); only_steering.setAttribute('checked', 'true'); only_steering.parentElement?.parentElement?.parentElement?.classList.remove('hidden'); only_steering.parentElement?.parentElement?.parentElement?.classList.remove('md:block'); only_steering.parentElement?.parentElement?.parentElement?.classList.remove('opacity-50'); } else { only_steering.setAttribute('disabled', 'disabled'); only_steering.removeAttribute('checked'); 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'); } } } } 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; const isShipmasterSteering = select.dataset.default_shipmaster_only_steering; setMaxAmountRowers(rowers, isShipmasterSteering); if (select.dataset.id) { choiceObjects['boat_id'].setChoiceByValue(select.dataset.id); } window.scrollTo(0, 0); 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; } }); }); } } 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 maxItemText: (maxItemCount) => { return `Nur ${maxItemCount} Ruderer können hinzugefügt werden`; }, }); choiceObjects[select.id] = choice; } function initToggle() { // get filter btns & set object sessionStorage const btns = <NodeListOf<HTMLButtonElement>>document.querySelectorAll('.filter-trips-js'); let filterObject = new Map(); 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()) { if(entry[0] === btn.dataset.action && entry[1] !== 'true') { filterMap.set(entry[0],'true'); } else { filterMap.set(entry[0],'false'); } } sessionStorage.setItem('tripsFilter', JSON.stringify( Array.from(filterMap.entries()))); } resetFilteredElements(); if(btn.getAttribute('aria-pressed') === 'false'){ Array.prototype.forEach.call(btns, (b: HTMLButtonElement) => { b.setAttribute('aria-pressed', 'false'); }); triggerFilterAction(btn.dataset.action); } else { btn.setAttribute('aria-pressed', 'false'); } }); }); } 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'); }); } } function triggerFilterAction(activeFilter: any) { const activeBtn = document.querySelector('button[data-action="' + activeFilter + '"]'); if(activeBtn) { activeBtn.setAttribute('aria-pressed', 'true'); filterAction(activeFilter); } } function filterAction(activeFilter: string) { switch(activeFilter) { case 'filter-days': { filterDays(); break; } case 'filter-coxs': { filterCoxs(); break; } case 'filter-months': { filterMonths(activeFilter) break; } } } function filterDays() { const daysNoTrips = document.querySelectorAll('div[data-trips="0"]'); Array.prototype.forEach.call(daysNoTrips, (day: HTMLElement) => { day.classList.toggle('hidden'); }); } 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'); }); }); } } } function initSearch() { const input = <HTMLInputElement>document.querySelector('#filter-js'); if(input) { filterElements(input.value); input.addEventListener('input', () => { filterElements(input.value); }); } } function filterElements(input: string) { 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'); } } 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(); if(triggerElement.dataset.trigger === 'sidebar') { initTripSidebar(triggerElement); } sidebar.toggle(); }); } }); } } function initTripSidebar(triggerElement: HTMLElement) { const sidebarElement = <HTMLElement>document.querySelector('#sidebar'); 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'); 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'; } }); 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'; } } }); if(bodyContainerElement) { bodyContainerElement.innerHTML = ''; bodyContainerElement.append(bodyElement); addRelationMagic(bodyElement); } if(triggerElement.dataset.day) { 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; } } } function addRelationMagic(bodyElement: HTMLElement) { const fields = bodyElement.querySelectorAll('.set-distance-js'); 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(); const dataList = <HTMLDataListElement>document.querySelector('#destinations'); 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'); }); }