engelsystem/resources/assets/js/forms.js

311 lines
8.4 KiB
JavaScript
Raw Normal View History

import Choices from 'choices.js';
import { formatDay, formatTime } from './date';
2022-11-29 19:19:30 +01:00
import { ready } from './ready';
/**
* Sets all checkboxes to the wanted state
2017-01-02 15:43:36 +01:00
*
* @param {string} id Id of the element containing all the checkboxes
* @param {boolean} checked True if the checkboxes should be checked
*/
2018-08-03 13:58:25 +02:00
global.checkAll = (id, checked) => {
document.querySelectorAll(`#${id} input[type="checkbox"]`).forEach((element) => {
2022-11-29 21:47:26 +01:00
element.checked = checked;
2022-11-26 14:50:59 +01:00
});
2018-08-12 13:01:03 +02:00
};
/**
* Sets the checkboxes according to the given type
*
* @param {string} id The Id of the element containing all the checkboxes
2022-11-29 21:47:26 +01:00
* @param {int[]} shiftsList A list of numbers
*/
global.checkOwnTypes = (id, shiftsList) => {
document.querySelectorAll(`#${id} input[type="checkbox"]`).forEach((element) => {
const value = Number(element.value);
2022-11-29 21:47:26 +01:00
element.checked = shiftsList.includes(value);
2022-11-26 14:50:59 +01:00
});
2018-08-12 13:01:03 +02:00
};
ready(() => {
/**
* @param {HTMLElement} element
*/
const triggerChange = (element) => {
const changeEvent = new Event('change');
element.dispatchEvent(changeEvent);
2023-01-03 20:20:46 +01:00
};
/**
* Sets a select value and triggers a change.
* If the select has a Choices.js instances, it uses this instead to set the value.
*
* @param {HTMLSelectElement} element
* @param {*} value
*/
const setSelectValue = (element, value) => {
if (element.choices) {
element.choices.setChoiceByValue(value);
}
element.value = value;
triggerChange(element);
};
/**
* Sets the values of the input fields with the IDs to from/to:
* - date portion of from start_day
* - time portion of from start_time
* - date portion of to end_day
* - time portion of to end_time
*
* @param {Date} from
* @param {Date} to
*/
const setInput = (from, to) => {
const fromDay = document.getElementById('start_day');
const fromTime = document.getElementById('start_time');
const toDay = document.getElementById('end_day');
const toTime = document.getElementById('end_time');
if (!fromDay || !fromTime || !toDay || !toTime) {
console.warn('cannot set input date because of missing field');
return;
}
setSelectValue(fromDay, formatDay(from));
fromTime.value = formatTime(from);
setSelectValue(toDay, formatDay(to));
toTime.value = formatTime(to);
};
/**
* @param {MouseEvent} event
*/
const onClickDate = (event) => {
const days = Number(event.currentTarget.dataset.days);
const from = new Date();
from.setHours(0, 0, 0, 0);
// add days, Date handles the overflow
from.setDate(from.getDate() + days);
const to = new Date(from);
to.setHours(23, 59);
setInput(from, to);
};
/**
* @param {MouseEvent} event
*/
const onClickTime = (event) => {
const hours = Number(event.currentTarget.dataset.hours);
const from = new Date();
const to = new Date(from);
// add hours, Date handles the overflow
to.setHours(to.getHours() + hours);
if (to < from) {
setInput(to, from);
2023-01-03 20:20:46 +01:00
} else {
setInput(from, to);
}
};
document.querySelectorAll('.set-date').forEach((element) => {
element.addEventListener('click', onClickDate);
});
document.querySelectorAll('.set-time').forEach((element) => {
element.addEventListener('click', onClickTime);
});
});
2022-11-29 21:47:26 +01:00
ready(() => {
2022-11-26 14:50:59 +01:00
/**
2022-11-29 21:47:26 +01:00
* Disable every submit button after clicking (to prevent double-clicking)
*/
document.querySelectorAll('form').forEach((formElement) => {
formElement.addEventListener('submit', () => {
document.querySelectorAll('input[type="submit"],button[type="submit"]').forEach((element) => {
element.readOnly = true;
element.classList.add('disabled');
});
});
2022-11-26 14:50:59 +01:00
});
});
/**
* {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled#overview}
*/
const DISABLE_ELEMENTS = [
2022-12-23 19:15:03 +01:00
'button',
'command',
'fieldset',
'input',
'keygen',
'optgroup',
'option',
'select',
'textarea',
];
ready(() => {
// get all input-radio's and add for each an onChange event listener
document.querySelectorAll('input[type="radio"]').forEach((radioElement) => {
// build selector and get all corrsponding elements for this input-radio
2022-12-23 19:15:03 +01:00
const selector = DISABLE_ELEMENTS.map(
(tagName) => `${tagName}[data-radio-name="${radioElement.name}"][data-radio-value]`
).join(',');
const elements = Array.from(document.querySelectorAll(selector));
// set all states one time on init for each of the corresponding elements
elements.forEach((element) => {
// each radio button updates only his elements
if (element.dataset.radioValue === radioElement.value) {
element.disabled = !radioElement.checked;
}
});
// add an onChange event listener that update the disabled state for all corresponding elements
radioElement.addEventListener('change', () => {
elements.forEach((element) => {
element.disabled = element.dataset.radioValue !== radioElement.value;
});
});
});
});
ready(() => {
document.querySelectorAll('.spinner-down').forEach((element) => {
const inputElement = document.getElementById(element.dataset.inputId);
if (inputElement) {
element.addEventListener('click', () => {
inputElement.stepDown();
});
}
});
document.querySelectorAll('.spinner-up').forEach((element) => {
const inputElement = document.getElementById(element.dataset.inputId);
if (inputElement) {
element.addEventListener('click', () => {
inputElement.stepUp();
});
}
});
});
/**
2018-12-05 18:43:51 +01:00
* Button to set current time in time input fields.
*/
2022-11-29 21:47:26 +01:00
ready(() => {
document.querySelectorAll('.input-group.time').forEach((element) => {
const button = element.querySelector('button');
if (!button) return;
button.addEventListener('click', () => {
2022-11-26 14:50:59 +01:00
const now = new Date();
2022-11-29 21:47:26 +01:00
const input = element.querySelector('input');
if (!input) return;
input.value = formatTime(now);
const daySelector = document.getElementById(input.id.replace('time', 'day'));
if (!daySelector) return;
const dayElements = daySelector.querySelectorAll('option');
2022-11-26 14:50:59 +01:00
const yyyyMMDD = formatDay(now);
2022-11-29 21:47:26 +01:00
dayElements.forEach((dayElement) => {
if (dayElement.value === yyyyMMDD) {
daySelector.value = dayElement.value;
2022-11-26 14:50:59 +01:00
return false;
}
});
2018-12-05 18:43:51 +01:00
});
2022-11-26 14:50:59 +01:00
});
2018-12-05 18:43:51 +01:00
});
2019-09-06 03:45:56 +02:00
2022-11-29 21:47:26 +01:00
ready(() => {
document.querySelectorAll('select').forEach((element) => {
element.choices = new Choices(element, {
allowHTML: false,
classNames: {
containerInner: 'choices__inner form-control',
},
fuseOptions: {
distance: 0,
ignoreLocation: true,
includeScore: true,
threshold: 0,
},
itemSelectText: '',
// do not use Number.MAX_SAFE_INTEGER here, because otherwise the script gets stuck
searchResultLimit: 9999,
});
2022-11-26 14:50:59 +01:00
});
2022-12-22 18:28:51 +01:00
});
2020-10-20 16:07:34 +02:00
2023-01-22 19:16:33 +01:00
/**
* Init Bootstrap Popover
*/
ready(() => {
document.querySelectorAll('[data-bs-toggle="popover"]').forEach((element) => new bootstrap.Popover(element));
});
2023-02-26 11:27:41 +01:00
/**
* Init Bootstrap Tooltips
*/
ready(() => {
document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach((element) => new bootstrap.Tooltip(element));
});
2020-11-15 18:47:30 +01:00
/**
* Show oauth buttons on welcome title click
*/
2022-11-29 21:47:26 +01:00
ready(() => {
[
['welcome-title', '.btn-group .btn.d-none'],
2022-11-29 21:47:26 +01:00
['settings-title', '.user-settings .nav-item'],
['oauth-settings-title', 'table tr.d-none'],
].forEach(([id, selector]) => {
document.getElementById(id)?.addEventListener('click', () => {
document.querySelectorAll(selector).forEach((element) => {
element.classList.remove('d-none');
});
});
2022-11-26 14:50:59 +01:00
});
2020-11-15 18:47:30 +01:00
});
2019-09-06 03:45:56 +02:00
/**
* Set the filter selects to latest state
*
* Uses DOMContentLoaded to prevent flickering
*/
2022-11-29 19:19:30 +01:00
ready(() => {
2022-11-26 14:50:59 +01:00
const filter = document.getElementById('collapseShiftsFilterSelect');
2022-11-29 21:47:26 +01:00
if (!filter || localStorage.getItem('collapseShiftsFilterSelect') !== 'hidden.bs.collapse') {
2022-11-26 14:50:59 +01:00
return;
}
2019-09-06 03:45:56 +02:00
2022-11-26 14:50:59 +01:00
filter.classList.remove('show');
2019-09-06 03:45:56 +02:00
});
2022-11-29 19:19:30 +01:00
ready(() => {
2022-12-22 18:28:51 +01:00
if (typeof localStorage === 'undefined') {
2022-11-26 14:50:59 +01:00
return;
}
2019-09-06 03:45:56 +02:00
/**
* @param {Event} event
*/
const onChange = (event) => {
localStorage.setItem('collapseShiftsFilterSelect', event.type);
2022-11-26 14:50:59 +01:00
};
2019-09-06 03:45:56 +02:00
2022-12-22 18:28:51 +01:00
document.getElementById('collapseShiftsFilterSelect')?.addEventListener('hidden.bs.collapse', onChange);
2022-11-29 21:47:26 +01:00
2022-12-22 18:28:51 +01:00
document.getElementById('collapseShiftsFilterSelect')?.addEventListener('shown.bs.collapse', onChange);
2019-09-06 03:45:56 +02:00
});