Files
luxtools-plugin/js/calendar-widget.js
2026-02-16 13:39:26 +01:00

130 lines
3.7 KiB
JavaScript

/* global window, document, fetch, URLSearchParams */
(function () {
'use strict';
var Luxtools = window.Luxtools || (window.Luxtools = {});
function findCalendarRoot(target) {
var el = target;
while (el && el !== document) {
if (el.classList && el.classList.contains('luxtools-calendar') && el.getAttribute('data-luxtools-calendar') === '1') {
return el;
}
el = el.parentNode;
}
return null;
}
function getNextMonth(year, month, direction) {
var cursor = new Date(year, month - 1, 1);
cursor.setMonth(cursor.getMonth() + direction);
return {
year: cursor.getFullYear(),
month: cursor.getMonth() + 1
};
}
function parseCalendarFromHtml(html) {
if (!html) return null;
var wrapper = document.createElement('div');
wrapper.innerHTML = html;
return wrapper.querySelector('div.luxtools-calendar[data-luxtools-calendar="1"]');
}
function setCalendarBusy(calendar, busy) {
if (!calendar) return;
if (busy) {
calendar.setAttribute('data-luxtools-loading', '1');
} else {
calendar.removeAttribute('data-luxtools-loading');
}
var buttons = calendar.querySelectorAll('button.luxtools-calendar-nav-button');
for (var i = 0; i < buttons.length; i++) {
buttons[i].disabled = !!busy;
}
}
function fetchCalendarMonth(calendar, year, month) {
var ajaxUrl = calendar.getAttribute('data-luxtools-ajax-url') || '';
if (!ajaxUrl) return Promise.reject(new Error('Missing calendar ajax url'));
var baseNs = calendar.getAttribute('data-base-ns') || 'chronological';
var params = new URLSearchParams({
call: 'luxtools_calendar_month',
year: String(year),
month: String(month),
base: baseNs
});
var url = ajaxUrl + (ajaxUrl.indexOf('?') >= 0 ? '&' : '?') + params.toString();
return fetch(url, {
method: 'GET',
credentials: 'same-origin',
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
}).then(function (response) {
if (!response.ok) {
throw new Error('Calendar request failed: ' + response.status);
}
return response.text();
});
}
function navigateCalendarMonth(calendar, direction) {
var year = parseInt(calendar.getAttribute('data-current-year') || '', 10);
var month = parseInt(calendar.getAttribute('data-current-month') || '', 10);
if (!year || !month) return;
var next = getNextMonth(year, month, direction);
setCalendarBusy(calendar, true);
fetchCalendarMonth(calendar, next.year, next.month)
.then(function (html) {
var replacement = parseCalendarFromHtml(html);
if (!replacement) {
throw new Error('Calendar markup missing in response');
}
calendar.replaceWith(replacement);
})
.catch(function () {
var fallbackLink = calendar.querySelector('a.luxtools-calendar-month-link');
if (fallbackLink && fallbackLink.href) {
window.location.href = fallbackLink.href;
}
})
.finally(function () {
setCalendarBusy(calendar, false);
});
}
function onCalendarClick(event) {
var target = event.target;
if (!target || !target.classList || !target.classList.contains('luxtools-calendar-nav-button')) return;
var calendar = findCalendarRoot(target);
if (!calendar) return;
var direction = parseInt(target.getAttribute('data-luxtools-dir') || '0', 10);
if (direction !== -1 && direction !== 1) return;
event.preventDefault();
navigateCalendarMonth(calendar, direction);
}
function initCalendarWidgets() {
document.addEventListener('click', onCalendarClick, false);
}
Luxtools.CalendarWidget = {
init: initCalendarWidgets
};
})();