/* global window, document, jQuery */
/**
* Event Popup, Day Popup, and Event CRUD
*
* - Clicking an event item with data-luxtools-event="1" opens a detail popup.
* - Clicking empty space in a calendar day cell opens a day popup listing all events.
* - Day popup includes a "Create Event" action for authenticated users.
* - Event popup includes "Edit" and "Delete" actions for authenticated users.
*/
(function () {
"use strict";
var Luxtools = window.Luxtools || (window.Luxtools = {});
// Temporary storage for form data when showing the recurring edit scope dialog
var _pendingEditFormData = null;
// ============================================================
// Shared helpers
// ============================================================
function escapeHtml(text) {
var div = document.createElement("div");
div.appendChild(document.createTextNode(text));
return div.innerHTML;
}
function pad2(value) {
return String(value).padStart(2, "0");
}
function formatDate(isoStr) {
if (!isoStr) return "";
var match = isoStr.match(/^(\d{4})-(\d{2})-(\d{2})/);
if (!match) return isoStr;
return match[3] + "." + match[2] + "." + match[1];
}
function formatDateTime(isoStr) {
if (!isoStr) return "";
return formatDate(isoStr) + " " + formatTimeOnly(isoStr);
}
function formatTimeOnly(isoStr) {
if (!isoStr) return "";
var match = isoStr.match(/T(\d{2}):(\d{2})/);
if (!match) return isoStr;
return match[1] + ":" + match[2];
}
function formatEventListTime(startIso, fallbackTime) {
var formatted = formatTimeOnly(startIso);
if (!formatted || formatted === startIso) {
return fallbackTime || "";
}
return formatted;
}
function isSameMoment(left, right) {
if (!left || !right) return false;
return left === right;
}
function getAjaxUrl() {
return (window.DOKU_BASE || "/") + "lib/exe/ajax.php";
}
function getSecurityToken(el) {
// Try element hierarchy
if (el) {
var container = el.closest ? el.closest("[data-luxtools-sectok]") : null;
if (container) {
var tok = container.getAttribute("data-luxtools-sectok");
if (tok) return tok;
}
}
if (window.JSINFO && window.JSINFO.sectok)
return String(window.JSINFO.sectok);
var input = document.querySelector(
'input[name="sectok"], input[name="securitytoken"]',
);
if (input && input.value) return String(input.value);
return "";
}
function isAuthenticated() {
// Check if user is logged in via JSINFO
if (window.JSINFO && window.JSINFO.isadmin) return true;
if (window.JSINFO && window.JSINFO.id !== undefined) {
// Check if user info exists (logged in users have a userinfo)
var userinfo = document.querySelector(".user");
if (userinfo) return true;
// Alternative: check for logout form
var logoutLink = document.querySelector(
'a[href*="do=logout"], .action.logout',
);
if (logoutLink) return true;
}
return false;
}
function showNotification(message, type) {
if (typeof window.msg === "function") {
var level = type === "error" ? -1 : type === "warning" ? 0 : 1;
window.msg(message, level);
return;
}
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);
}
// Lazy reference to the shared dialog infrastructure (dialog.js).
// Accessed via function to handle any script-loading order variation.
function getDialog() {
return Luxtools.Dialog;
}
// ============================================================
// Event Popup (single event detail)
// ============================================================
var EventPopup = (function () {
/**
* Open event detail popup.
* @param {Element} el - Element with data-event-* attributes
* @param {object} [opts] - Options
* @param {boolean} [opts.hideDatetime] - Hide the date/time field (when opened from day context)
*/
function open(el, opts) {
opts = opts || {};
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 uid = el.getAttribute("data-event-uid") || "";
var recurrence = el.getAttribute("data-event-recurrence") || "";
var dateIso = el.getAttribute("data-event-date") || "";
var html = '
';
html +=
'';
html +=
'
' + escapeHtml(summary) + "
";
// Date/time - hide when opened from a day context
if (!opts.hideDatetime) {
html += '
';
if (allDay) {
html += "Date: " + formatDate(start);
if (end && !isSameMoment(start, end)) {
html += " – " + formatDate(end);
}
} else {
html += "Time: " + formatDateTime(start);
if (end && !isSameMoment(start, end)) {
html += " – " + formatDateTime(end);
}
}
html += "
";
} else if (!allDay && start) {
// In day context, show only time (not date)
html += '
';
html += "Time: " + formatTimeOnly(start);
if (end && !isSameMoment(start, end)) {
html += " – " + formatTimeOnly(end);
}
html += "