/* global window, document, jQuery */ /** * Event Popup and Maintenance Task Handling * * - Clicking an event item with data-luxtools-event="1" opens a detail popup. * - Clicking a maintenance task action button sends an AJAX request to * complete/reopen the task. */ (function () { 'use strict'; var Luxtools = window.Luxtools || (window.Luxtools = {}); // ============================================================ // Event Popup // ============================================================ var EventPopup = (function () { var overlay = null; var popup = null; function ensureElements() { if (overlay) return; overlay = document.createElement('div'); overlay.className = 'luxtools-event-popup-overlay'; overlay.style.display = 'none'; popup = document.createElement('div'); popup.className = 'luxtools-event-popup'; popup.setAttribute('role', 'dialog'); popup.setAttribute('aria-modal', 'true'); overlay.appendChild(popup); document.body.appendChild(overlay); overlay.addEventListener('click', function (e) { if (e.target === overlay) { close(); } }); document.addEventListener('keydown', function (e) { if (e.key === 'Escape' && overlay.style.display !== 'none') { close(); } }); } function open(el) { ensureElements(); var summary = el.getAttribute('data-event-summary') || ''; var start = el.getAttribute('data-event-start') || ''; var end = el.getAttribute('data-event-end') || ''; var location = el.getAttribute('data-event-location') || ''; var description = el.getAttribute('data-event-description') || ''; var allDay = el.getAttribute('data-event-allday') === '1'; var slot = el.getAttribute('data-event-slot') || ''; var html = '
'; html += ''; html += '

' + escapeHtml(summary) + '

'; // Date/time html += '
'; if (allDay) { html += 'Date: ' + formatDate(start); if (end) { html += ' – ' + formatDate(end); } } else { html += 'Time: ' + formatDateTime(start); if (end) { html += ' – ' + formatDateTime(end); } } html += '
'; if (location) { html += '
Location: ' + escapeHtml(location) + '
'; } if (description) { html += '
' + 'Description:
' + escapeHtml(description).replace(/\n/g, '
') + '
'; } if (slot) { html += '
' + escapeHtml(slot) + '
'; } html += '
'; popup.innerHTML = html; overlay.style.display = 'flex'; // Close button inside popup var closeBtn = popup.querySelector('.luxtools-event-popup-close'); if (closeBtn) { closeBtn.addEventListener('click', close); } } function close() { if (overlay) { overlay.style.display = 'none'; } } function formatDate(isoStr) { if (!isoStr) return ''; var d = new Date(isoStr); if (isNaN(d.getTime())) return isoStr; return d.toLocaleDateString(); } function formatDateTime(isoStr) { if (!isoStr) return ''; var d = new Date(isoStr); if (isNaN(d.getTime())) return isoStr; return d.toLocaleDateString() + ' ' + d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' }); } function escapeHtml(text) { var div = document.createElement('div'); div.appendChild(document.createTextNode(text)); return div.innerHTML; } return { open: open, close: close, }; })(); // ============================================================ // Maintenance Task Actions // ============================================================ var MaintenanceTasks = (function () { function handleAction(button) { var action = button.getAttribute('data-action'); if (!action) return; // Find the containing list item or container with task data var item = button.closest('[data-task-uid]'); if (!item) { // Try the syntax plugin format item = button.closest('[data-uid]'); } if (!item) return; var uid = item.getAttribute('data-task-uid') || item.getAttribute('data-uid') || ''; var date = item.getAttribute('data-task-date') || item.getAttribute('data-date') || ''; var recurrence = item.getAttribute('data-task-recurrence') || item.getAttribute('data-recurrence') || ''; if (!uid || !date) return; // Find AJAX URL and security token from parent container or global var container = item.closest('[data-luxtools-ajax-url]'); var ajaxUrl = container ? container.getAttribute('data-luxtools-ajax-url') : ''; var sectok = container ? container.getAttribute('data-luxtools-sectok') : ''; if (!ajaxUrl) { // Fallback: use DokuWiki's standard AJAX endpoint ajaxUrl = (window.DOKU_BASE || '/') + 'lib/exe/ajax.php'; } if (!sectok && window.JSINFO && window.JSINFO.sectok) { sectok = window.JSINFO.sectok; } button.disabled = true; button.textContent = '...'; var params = 'call=luxtools_maintenance_task' + '&action=' + encodeURIComponent(action) + '&uid=' + encodeURIComponent(uid) + '&date=' + encodeURIComponent(date) + '&recurrence=' + encodeURIComponent(recurrence) + '§ok=' + encodeURIComponent(sectok); var xhr = new XMLHttpRequest(); xhr.open('POST', ajaxUrl, true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onload = function () { var result; try { result = JSON.parse(xhr.responseText); } catch (e) { result = { ok: false, error: 'Invalid response' }; } if (result.ok) { // Visual feedback: mark item as done or revert if (action === 'complete') { item.classList.add('luxtools-task-completed'); // Fade out and remove after a short delay item.style.opacity = '0.5'; setTimeout(function () { item.style.display = 'none'; }, 1000); } else { item.classList.remove('luxtools-task-completed'); item.style.opacity = '1'; button.textContent = 'Complete'; button.setAttribute('data-action', 'complete'); button.disabled = false; } // Show remote write warning if applicable if (result.remoteOk === false && result.remoteError) { showNotification(result.remoteError, 'warning'); } } else { var errMsg = result.error || 'Action failed'; showNotification(errMsg, 'error'); button.textContent = action === 'complete' ? 'Complete' : 'Reopen'; button.disabled = false; } }; xhr.onerror = function () { showNotification('Network error', 'error'); button.textContent = action === 'complete' ? 'Complete' : 'Reopen'; button.disabled = false; }; xhr.send(params); } function showNotification(message, type) { // Use DokuWiki msg() if available if (typeof window.msg === 'function') { var level = (type === 'error') ? -1 : ((type === 'warning') ? 0 : 1); window.msg(message, level); return; } // Fallback: simple notification var notif = document.createElement('div'); notif.className = 'luxtools-notification luxtools-notification-' + type; notif.textContent = message; document.body.appendChild(notif); setTimeout(function () { if (notif.parentNode) notif.parentNode.removeChild(notif); }, 5000); } return { handleAction: handleAction, }; })(); // ============================================================ // Event Delegation // ============================================================ document.addEventListener('click', function (e) { var target = e.target; // Maintenance task action buttons (day pages) if (target.classList && target.classList.contains('luxtools-task-action')) { e.preventDefault(); MaintenanceTasks.handleAction(target); return; } // Maintenance task complete buttons (syntax plugin list) if (target.classList && target.classList.contains('luxtools-task-complete-btn')) { e.preventDefault(); MaintenanceTasks.handleAction(target); return; } // Event popup: find closest element with data-luxtools-event var eventEl = target.closest ? target.closest('[data-luxtools-event]') : null; if (!eventEl) { // Traverse manually for older browsers var el = target; while (el && el !== document) { if (el.getAttribute && el.getAttribute('data-luxtools-event') === '1') { eventEl = el; break; } el = el.parentNode; } } if (eventEl) { // Don't open popup if clicking a button inside the event item if (target.tagName === 'BUTTON' || target.closest('button')) return; e.preventDefault(); EventPopup.open(eventEl); } }, false); Luxtools.EventPopup = EventPopup; Luxtools.MaintenanceTasks = MaintenanceTasks; })();