diff --git a/action.php b/action.php
index 03b25bf..d031f2e 100644
--- a/action.php
+++ b/action.php
@@ -82,12 +82,6 @@ class action_plugin_luxtools extends ActionPlugin
$this,
"handleCalendarWidgetAjax",
);
- $controller->register_hook(
- "AJAX_CALL_UNKNOWN",
- "BEFORE",
- $this,
- "handleMaintenanceTaskAction",
- );
$controller->register_hook(
"AJAX_CALL_UNKNOWN",
"BEFORE",
@@ -753,21 +747,8 @@ class action_plugin_luxtools extends ActionPlugin
);
}
- // Render maintenance tasks
- if (isset($grouped["maintenance"])) {
- $title = (string) $this->getLang("chronological_maintenance_title");
- if ($title === "") {
- $title = "Tasks";
- }
- $html .= $this->renderMaintenanceSection(
- $grouped["maintenance"],
- $title,
- $dateIso,
- );
- }
-
- // Render slot3/slot4 if present
- foreach (["slot3", "slot4"] as $slotKey) {
+ // Render slot2/slot3/slot4 if present
+ foreach (["slot2", "slot3", "slot4"] as $slotKey) {
if (isset($grouped[$slotKey]) && isset($slots[$slotKey])) {
$label = $slots[$slotKey]->getLabel();
$html .= $this->renderEventSection(
@@ -814,51 +795,6 @@ class action_plugin_luxtools extends ActionPlugin
"";
}
- /**
- * Render a maintenance task section with completion buttons.
- *
- * @param CalendarEvent[] $events
- * @param string $title
- * @param string $dateIso
- * @return string
- */
- protected function renderMaintenanceSection(
- array $events,
- string $title,
- string $dateIso,
- ): string {
- $items = "";
- $ajaxUrl = defined("DOKU_BASE")
- ? (string) DOKU_BASE . "lib/exe/ajax.php"
- : "lib/exe/ajax.php";
-
- foreach ($events as $event) {
- $items .= $this->renderMaintenanceListItem($event, $ajaxUrl);
- }
- if ($items === "") {
- return "";
- }
-
- $secToken = function_exists("getSecurityToken")
- ? getSecurityToken()
- : "";
-
- return '
' .
- "
" .
- hsc($title) .
- "
" .
- "
" .
- "
";
- }
-
/**
* Render a single event as a list item with popup data attributes.
*
@@ -921,215 +857,6 @@ class action_plugin_luxtools extends ActionPlugin
"";
}
- /**
- * Render a maintenance task as a list item with completion button.
- *
- * @param CalendarEvent $event
- * @param string $ajaxUrl
- * @return string
- */
- protected function renderMaintenanceListItem(
- CalendarEvent $event,
- string $ajaxUrl,
- ): string {
- $isCompleted = $event->isCompleted();
- $classes = "luxtools-maintenance-task";
- if ($isCompleted) {
- $classes .= " luxtools-task-completed";
- }
-
- $summaryHtml = hsc($event->summary);
-
- // Data attributes for popup and completion
- $dataAttrs = ' data-luxtools-event="1"';
- $dataAttrs .= ' data-event-summary="' . hsc($event->summary) . '"';
- $dataAttrs .= ' data-event-start="' . hsc($event->startIso) . '"';
- if ($event->endIso !== "") {
- $dataAttrs .= ' data-event-end="' . hsc($event->endIso) . '"';
- }
- if ($event->location !== "") {
- $dataAttrs .=
- ' data-event-location="' . hsc($event->location) . '"';
- }
- if ($event->description !== "") {
- $dataAttrs .=
- ' data-event-description="' . hsc($event->description) . '"';
- }
- $dataAttrs .=
- ' data-event-allday="' . ($event->allDay ? "1" : "0") . '"';
- $dataAttrs .= ' data-event-slot="maintenance"';
- $dataAttrs .= ' data-task-uid="' . hsc($event->uid) . '"';
- $dataAttrs .= ' data-task-date="' . hsc($event->dateIso) . '"';
- $dataAttrs .=
- ' data-task-recurrence="' . hsc($event->recurrenceId) . '"';
- $dataAttrs .= ' data-task-status="' . hsc($event->status) . '"';
-
- $buttonLabel = $isCompleted
- ? (string) $this->getLang("maintenance_task_reopen")
- : (string) $this->getLang("maintenance_task_complete");
- if ($buttonLabel === "") {
- $buttonLabel = $isCompleted ? "Reopen" : "Complete";
- }
- $buttonAction = $isCompleted ? "reopen" : "complete";
-
- $buttonHtml =
- '";
-
- $timeHtml = "";
- if (!$event->allDay && $event->time !== "") {
- $timeHtml =
- '' .
- hsc($event->time) .
- " - ";
- }
-
- return '" .
- $timeHtml .
- '' .
- $summaryHtml .
- " " .
- $buttonHtml .
- "";
- }
-
- /**
- * Handle AJAX requests for marking maintenance tasks complete/reopen.
- *
- * @param Event $event
- * @param mixed $param
- * @return void
- */
- public function handleMaintenanceTaskAction(Event $event, $param)
- {
- if ($event->data !== "luxtools_maintenance_task") {
- return;
- }
-
- $event->preventDefault();
- $event->stopPropagation();
-
- header("Content-Type: application/json; charset=utf-8");
- $this->sendNoStoreHeaders();
-
- global $INPUT;
-
- // Verify security token
- if (!checkSecurityToken()) {
- http_status(403);
- echo json_encode([
- "ok" => false,
- "error" => "Security token mismatch",
- ]);
- return;
- }
-
- $action = $INPUT->str("action"); // 'complete' or 'reopen'
- $uid = $INPUT->str("uid");
- $dateIso = $INPUT->str("date");
- $recurrence = $INPUT->str("recurrence");
-
- if (!in_array($action, ["complete", "reopen"], true)) {
- http_status(400);
- echo json_encode(["ok" => false, "error" => "Invalid action"]);
- return;
- }
- if ($uid === "" || !ChronoID::isIsoDate($dateIso)) {
- http_status(400);
- echo json_encode(["ok" => false, "error" => "Missing uid or date"]);
- return;
- }
-
- $slots = CalendarSlot::loadAll($this);
- $maintenanceSlot = $slots["maintenance"] ?? null;
- if ($maintenanceSlot === null || !$maintenanceSlot->isEnabled()) {
- http_status(400);
- echo json_encode([
- "ok" => false,
- "error" => "Maintenance calendar not configured",
- ]);
- return;
- }
-
- $newStatus = $action === "complete" ? "COMPLETED" : "TODO";
-
- // Update local ICS file
- $localOk = false;
- $file = $maintenanceSlot->getFile();
- if ($file !== "" && is_file($file)) {
- $localOk = IcsWriter::updateEventStatus(
- $file,
- $uid,
- $recurrence,
- $newStatus,
- $dateIso,
- );
- }
-
- if (!$localOk) {
- http_status(500);
- echo json_encode([
- "ok" => false,
- "error" => $this->getLang("maintenance_complete_error"),
- ]);
- return;
- }
-
- // Clear caches so next render picks up changes
- CalendarService::clearCache();
-
- // Remote CalDAV write-back if configured
- $remoteOk = true;
- $remoteError = "";
- if ($maintenanceSlot->hasRemoteSource()) {
- try {
- $caldavResult = CalDavClient::updateEventStatus(
- $maintenanceSlot->getCaldavUrl(),
- $maintenanceSlot->getUsername(),
- $maintenanceSlot->getPassword(),
- $uid,
- $recurrence,
- $newStatus,
- $dateIso,
- );
- if ($caldavResult !== "") {
- $remoteOk = false;
- $remoteError =
- $this->getLang("maintenance_remote_write_failed") .
- ": " .
- $caldavResult;
- }
- } catch (Throwable $e) {
- $remoteOk = false;
- $remoteError =
- $this->getLang("maintenance_remote_write_failed") .
- ": " .
- $e->getMessage();
- }
- }
-
- $msg =
- $action === "complete"
- ? $this->getLang("maintenance_complete_success")
- : $this->getLang("maintenance_reopen_success");
-
- echo json_encode([
- "ok" => true,
- "message" => $msg,
- "remoteOk" => $remoteOk,
- "remoteError" => $remoteError,
- ]);
- }
-
/**
* Handle AJAX requests for manual calendar sync.
*
diff --git a/admin/main.php b/admin/main.php
index 85560fd..e0bad8a 100644
--- a/admin/main.php
+++ b/admin/main.php
@@ -9,7 +9,7 @@ if (!defined('DOKU_INC')) die();
class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
{
/** @var string[] Calendar slot keys */
- protected $calendarSlotKeys = ['general', 'maintenance', 'slot3', 'slot4'];
+ protected $calendarSlotKeys = ['general', 'slot2', 'slot3', 'slot4'];
/** @var string[] */
protected $configKeys = [
@@ -38,12 +38,12 @@ class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
'calendar_general_password',
'calendar_general_color',
'calendar_general_display',
- 'calendar_maintenance_file',
- 'calendar_maintenance_caldav_url',
- 'calendar_maintenance_username',
- 'calendar_maintenance_password',
- 'calendar_maintenance_color',
- 'calendar_maintenance_display',
+ 'calendar_slot2_file',
+ 'calendar_slot2_caldav_url',
+ 'calendar_slot2_username',
+ 'calendar_slot2_password',
+ 'calendar_slot2_color',
+ 'calendar_slot2_display',
'calendar_slot3_file',
'calendar_slot3_caldav_url',
'calendar_slot3_username',
@@ -278,9 +278,9 @@ class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
// Calendar slot settings
$slotLabels = [
'general' => 'General',
- 'maintenance' => 'Maintenance',
- 'slot3' => 'Slot 3',
- 'slot4' => 'Slot 4',
+ 'slot2' => 'Slot 2',
+ 'slot3' => 'Slot 3',
+ 'slot4' => 'Slot 4',
];
$displayOptions = [
'none' => (string)$this->getLang('calendar_slot_display_none'),
diff --git a/conf/default.php b/conf/default.php
index 8dce750..7acbbe3 100644
--- a/conf/default.php
+++ b/conf/default.php
@@ -37,7 +37,7 @@ $conf['open_service_url'] = 'http://127.0.0.1:8765';
// Base filesystem path for chronological photo integration.
$conf['image_base_path'] = '';
-// Calendar slot configuration (4 slots: general, maintenance, slot3, slot4)
+// Calendar slot configuration (4 slots: general, slot2, slot3, slot4)
// Each slot has: file, caldav_url, username, password, color, display
$conf['calendar_general_file'] = '';
$conf['calendar_general_caldav_url'] = '';
@@ -46,12 +46,12 @@ $conf['calendar_general_password'] = '';
$conf['calendar_general_color'] = '#4a90d9';
$conf['calendar_general_display'] = 'none';
-$conf['calendar_maintenance_file'] = '';
-$conf['calendar_maintenance_caldav_url'] = '';
-$conf['calendar_maintenance_username'] = '';
-$conf['calendar_maintenance_password'] = '';
-$conf['calendar_maintenance_color'] = '#e67e22';
-$conf['calendar_maintenance_display'] = 'none';
+$conf['calendar_slot2_file'] = '';
+$conf['calendar_slot2_caldav_url'] = '';
+$conf['calendar_slot2_username'] = '';
+$conf['calendar_slot2_password'] = '';
+$conf['calendar_slot2_color'] = '#e67e22';
+$conf['calendar_slot2_display'] = 'none';
$conf['calendar_slot3_file'] = '';
$conf['calendar_slot3_caldav_url'] = '';
diff --git a/js/event-popup.js b/js/event-popup.js
index a7da062..8ed6434 100644
--- a/js/event-popup.js
+++ b/js/event-popup.js
@@ -1,14 +1,12 @@
/* global window, document, jQuery */
/**
- * Event Popup, Day Popup, Event CRUD, and Maintenance Task Handling
+ * 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.
- * - Clicking a maintenance task action button sends an AJAX request to
- * complete/reopen the task.
*/
(function () {
"use strict";
@@ -889,99 +887,6 @@
return { confirmDelete: confirmDelete, executeDelete: executeDelete };
})();
- // ============================================================
- // Maintenance Task Actions
- // ============================================================
- var MaintenanceTasks = (function () {
- function handleAction(button) {
- var action = button.getAttribute("data-action");
- if (!action) return;
-
- var item = button.closest("[data-task-uid]");
- if (!item) 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;
-
- var ajaxUrl = getAjaxUrl();
- var sectok = getSecurityToken(item);
-
- 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) {
- if (action === "complete") {
- item.classList.add("luxtools-task-completed");
- button.textContent = "Reopen";
- button.setAttribute("data-action", "reopen");
- } else {
- item.classList.remove("luxtools-task-completed");
- item.style.opacity = "1";
- button.textContent = "Complete";
- button.setAttribute("data-action", "complete");
- }
- button.disabled = false;
-
- if (result.remoteOk === false && result.remoteError) {
- showNotification(result.remoteError, "warning");
- }
- } else {
- showNotification(result.error || "Action failed", "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);
- }
-
- return { handleAction: handleAction };
- })();
-
// ============================================================
// Event Delegation
// ============================================================
@@ -990,26 +895,6 @@
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 form save
if (
target.classList &&
@@ -1166,5 +1051,4 @@
Luxtools.EventPopup = EventPopup;
Luxtools.DayPopup = DayPopup;
- Luxtools.MaintenanceTasks = MaintenanceTasks;
})();
diff --git a/lang/de/lang.php b/lang/de/lang.php
index 9f5e89f..94c9c91 100644
--- a/lang/de/lang.php
+++ b/lang/de/lang.php
@@ -95,14 +95,6 @@ $lang["pagelink_unlinked"] = "Seite nicht verknüpft";
$lang["pagelink_multi_warning"] = "Mehrere Ordner verknüpft";
$lang["chronological_photos_title"] = "Fotos";
$lang["chronological_events_title"] = "Termine";
-$lang["chronological_maintenance_title"] = "Aufgaben";
-$lang["maintenance_task_complete"] = "Erledigen";
-$lang["maintenance_task_reopen"] = "Wieder öffnen";
-$lang["maintenance_no_tasks"] = "Keine offenen Aufgaben.";
-$lang["maintenance_complete_success"] = "Aufgabe als erledigt markiert.";
-$lang["maintenance_complete_error"] = "Aktualisierung der Aufgabe fehlgeschlagen.";
-$lang["maintenance_reopen_success"] = "Aufgabe wieder geöffnet.";
-$lang["maintenance_remote_write_failed"] = "Lokale Aktualisierung erfolgreich, aber CalDAV-Update fehlgeschlagen. Wird bei nächster Synchronisierung erneut versucht.";
$lang["calendar_sync_button"] = "Kalender synchronisieren";
$lang["calendar_sync_success"] = "Kalender-Synchronisierung abgeschlossen.";
$lang["calendar_sync_error"] = "Kalender-Synchronisierung fehlgeschlagen.";
diff --git a/lang/en/lang.php b/lang/en/lang.php
index f7e78c6..4ab8705 100644
--- a/lang/en/lang.php
+++ b/lang/en/lang.php
@@ -96,14 +96,6 @@ $lang["pagelink_multi_warning"] = "Multiple folders linked";
$lang["calendar_err_badmonth"] = "Invalid calendar month. Use YYYY-MM.";
$lang["chronological_photos_title"] = "Photos";
$lang["chronological_events_title"] = "Events";
-$lang["chronological_maintenance_title"] = "Tasks";
-$lang["maintenance_task_complete"] = "Complete";
-$lang["maintenance_task_reopen"] = "Reopen";
-$lang["maintenance_no_tasks"] = "No open tasks.";
-$lang["maintenance_complete_success"] = "Task marked as completed.";
-$lang["maintenance_complete_error"] = "Failed to update task.";
-$lang["maintenance_reopen_success"] = "Task reopened.";
-$lang["maintenance_remote_write_failed"] = "Local update succeeded, but remote CalDAV update failed. Will retry on next sync.";
$lang["calendar_sync_button"] = "Sync Calendars";
$lang["calendar_sync_success"] = "Calendar sync completed.";
$lang["calendar_sync_error"] = "Calendar sync failed.";
diff --git a/src/CalendarEvent.php b/src/CalendarEvent.php
index 44a8c01..dcdef58 100644
--- a/src/CalendarEvent.php
+++ b/src/CalendarEvent.php
@@ -10,7 +10,7 @@ namespace dokuwiki\plugin\luxtools;
*/
class CalendarEvent
{
- /** @var string Calendar slot key (e.g. 'general', 'maintenance') */
+ /** @var string Calendar slot key (e.g. 'general', 'slot2') */
public $slotKey;
/** @var string Unique source event UID */
@@ -52,35 +52,4 @@ class CalendarEvent
/** @var string The date (YYYY-MM-DD) this event applies to */
public $dateIso;
-
- /**
- * Build a stable completion key for maintenance task tracking.
- *
- * @return string
- */
- public function completionKey(): string
- {
- return implode('|', [$this->slotKey, $this->uid, $this->dateIso]);
- }
-
- /**
- * Whether this event/task is marked as completed.
- *
- * @return bool
- */
- public function isCompleted(): bool
- {
- $s = strtoupper($this->status);
- return $s === 'COMPLETED';
- }
-
- /**
- * Whether this event/task is open (for maintenance filtering).
- *
- * @return bool
- */
- public function isOpen(): bool
- {
- return !$this->isCompleted();
- }
}
diff --git a/src/CalendarService.php b/src/CalendarService.php
index d650e33..e7b9a9d 100644
--- a/src/CalendarService.php
+++ b/src/CalendarService.php
@@ -14,17 +14,13 @@ use Throwable;
/**
* Slot-aware calendar service.
*
- * Provides normalized event data grouped by slot for rendering,
- * widget indicators, task list queries, and completion tracking.
+ * Provides normalized event data grouped by slot for rendering and widget indicators.
*/
class CalendarService
{
/** @var array In-request cache keyed by "slotKey|dateIso" */
protected static $dayCache = [];
- /** @var array In-request cache keyed by "slotKey|all" for open tasks */
- protected static $taskCache = [];
-
/** @var array In-request cache keyed by file path */
protected static $vcalCache = [];
@@ -111,81 +107,6 @@ class CalendarService
return self::slotEventsForDate($slot, $dateIso) !== [];
}
- /**
- * Get all open maintenance tasks due up to (and including) today.
- *
- * @param CalendarSlot $maintenanceSlot
- * @param string $todayIso YYYY-MM-DD
- * @param int $pastDays Maximum number of overdue days to include
- * @return CalendarEvent[] Sorted: overdue first, then today, then by title
- */
- public static function openMaintenanceTasks(CalendarSlot $maintenanceSlot, string $todayIso, int $pastDays = 30): array
- {
- if (!$maintenanceSlot->isEnabled()) return [];
- if (!ChronoID::isIsoDate($todayIso)) return [];
-
- $pastDays = max(0, $pastDays);
-
- $file = $maintenanceSlot->getFile();
- if ($file === '' || !is_file($file) || !is_readable($file)) return [];
-
- $cacheKey = $maintenanceSlot->getKey() . '|tasks|' . $todayIso . '|' . $pastDays;
- if (isset(self::$taskCache[$cacheKey])) {
- return self::$taskCache[$cacheKey];
- }
-
- $tasks = self::parseAllTasksFromFile($file, $maintenanceSlot->getKey(), $todayIso);
- $oldestOpenDateIso = self::oldestOpenTaskDate($todayIso, $pastDays);
-
- // Filter: only non-completed, due today or earlier, and not older than the configured overdue window.
- $open = [];
- foreach ($tasks as $task) {
- if ($task->isCompleted()) continue;
- if ($task->dateIso > $todayIso) continue;
- if ($task->dateIso < $oldestOpenDateIso) continue;
- $open[] = $task;
- }
-
- // Sort: overdue first, then today, then by time, then by title
- usort($open, static function (CalendarEvent $a, CalendarEvent $b) use ($todayIso): int {
- $aOverdue = $a->dateIso < $todayIso;
- $bOverdue = $b->dateIso < $todayIso;
- if ($aOverdue !== $bOverdue) {
- return $aOverdue ? -1 : 1;
- }
- $dateCmp = strcmp($a->dateIso, $b->dateIso);
- if ($dateCmp !== 0) return $dateCmp;
-
- $timeCmp = strcmp($a->time, $b->time);
- if ($timeCmp !== 0) return $timeCmp;
-
- return strcmp($a->summary, $b->summary);
- });
-
- self::$taskCache[$cacheKey] = $open;
- return $open;
- }
-
- /**
- * @param string $todayIso
- * @param int $pastDays
- * @return string
- */
- protected static function oldestOpenTaskDate(string $todayIso, int $pastDays): string
- {
- try {
- $today = new DateTimeImmutable($todayIso . ' 00:00:00', new DateTimeZone('UTC'));
- } catch (Throwable $e) {
- return $todayIso;
- }
-
- if ($pastDays === 0) {
- return $today->format('Y-m-d');
- }
-
- return $today->sub(new DateInterval('P' . $pastDays . 'D'))->format('Y-m-d');
- }
-
/**
* Get slot-level day indicator data for a whole month.
*
@@ -329,49 +250,6 @@ class CalendarService
}
}
- /**
- * Parse all tasks (VEVENT with STATUS) from a maintenance file,
- * expanding recurrences up to the given date.
- *
- * @param string $file
- * @param string $slotKey
- * @param string $todayIso
- * @return CalendarEvent[]
- */
- protected static function parseAllTasksFromFile(string $file, string $slotKey, string $todayIso): array
- {
- $calendar = self::readCalendar($file);
- if ($calendar === null) return [];
-
- try {
- $component = $calendar;
-
- // Expand from a reasonable lookback to tomorrow
- $utc = new DateTimeZone('UTC');
- $rangeStart = new DateTimeImmutable('2020-01-01 00:00:00', $utc);
- $rangeEnd = new DateTimeImmutable($todayIso . ' 00:00:00', $utc);
- $rangeEnd = $rangeEnd->add(new DateInterval('P1D'));
-
- $expanded = $component->expand($rangeStart, $rangeEnd);
- if (!($expanded instanceof VCalendar)) return [];
-
- $tasks = [];
-
- // Collect VEVENTs
- foreach ($expanded->select('VEVENT') as $vevent) {
- if (!($vevent instanceof VEvent)) continue;
- $event = self::normalizeVEvent($vevent, $slotKey);
- if ($event !== null) {
- $tasks[] = $event;
- }
- }
-
- return $tasks;
- } catch (Throwable $e) {
- return [];
- }
- }
-
/**
* Collect normalized events from an expanded VCalendar for a specific date.
*
@@ -440,42 +318,6 @@ class CalendarService
return $event;
}
- /**
- * Normalize a VEVENT into a CalendarEvent (without day filtering).
- *
- * @param VEvent $vevent
- * @param string $slotKey
- * @return CalendarEvent|null
- */
- protected static function normalizeVEvent(VEvent $vevent, string $slotKey): ?CalendarEvent
- {
- if (!isset($vevent->DTSTART)) return null;
-
- $isAllDay = strtoupper((string)($vevent->DTSTART['VALUE'] ?? '')) === 'DATE';
- $start = self::toImmutable($vevent->DTSTART->getDateTime());
- if ($start === null) return null;
-
- $end = self::resolveEnd($vevent, $start, $isAllDay);
-
- $event = new CalendarEvent();
- $event->slotKey = $slotKey;
- $event->uid = trim((string)($vevent->UID ?? ''));
- $event->recurrenceId = isset($vevent->{'RECURRENCE-ID'}) ? trim((string)$vevent->{'RECURRENCE-ID'}) : '';
- $event->summary = trim((string)($vevent->SUMMARY ?? ''));
- if ($event->summary === '') $event->summary = '(ohne Titel)';
- $event->startIso = $start->format(DateTimeInterface::ATOM);
- $event->endIso = $end->format(DateTimeInterface::ATOM);
- $event->allDay = $isAllDay;
- $event->time = $isAllDay ? '' : $start->format('H:i');
- $event->location = trim((string)($vevent->LOCATION ?? ''));
- $event->description = trim((string)($vevent->DESCRIPTION ?? ''));
- $event->status = strtoupper(trim((string)($vevent->STATUS ?? '')));
- $event->componentType = 'VEVENT';
- $event->dateIso = $start->format('Y-m-d');
-
- return $event;
- }
-
/**
* Resolve the end date/time for a VEVENT.
*
@@ -573,7 +415,6 @@ class CalendarService
public static function clearCache(): void
{
self::$dayCache = [];
- self::$taskCache = [];
self::$vcalCache = [];
}
}
diff --git a/src/CalendarSlot.php b/src/CalendarSlot.php
index 7022729..d929aac 100644
--- a/src/CalendarSlot.php
+++ b/src/CalendarSlot.php
@@ -12,17 +12,17 @@ namespace dokuwiki\plugin\luxtools;
class CalendarSlot
{
/** @var string[] Ordered list of all supported slot keys */
- public const SLOT_KEYS = ['general', 'maintenance', 'slot3', 'slot4'];
+ public const SLOT_KEYS = ['general', 'slot2', 'slot3', 'slot4'];
/** @var string[] Allowed widget indicator display positions */
public const INDICATOR_DISPLAYS = ['none', 'top-left', 'top-right', 'bottom-left', 'bottom-right'];
/** @var array Human-readable labels for slot keys */
public const SLOT_LABELS = [
- 'general' => 'General',
- 'maintenance' => 'Maintenance',
- 'slot3' => 'Slot 3',
- 'slot4' => 'Slot 4',
+ 'general' => 'General',
+ 'slot2' => 'Slot 2',
+ 'slot3' => 'Slot 3',
+ 'slot4' => 'Slot 4',
];
/** @var string */
diff --git a/style.css b/style.css
index d91986d..64ece8a 100644
--- a/style.css
+++ b/style.css
@@ -724,7 +724,7 @@ div.luxtools-calendar
/* ============================================================
* Calendar Widget Indicators
* Colored corner markers showing which slots have events on a day.
- * Positions: general=top-left, maintenance=top-right,
+ * Positions: general=top-left, slot2=top-right,
* slot3=bottom-right, slot4=bottom-left (clockwise)
* ============================================================ */
div.luxtools-calendar td.luxtools-calendar-day {
@@ -926,78 +926,6 @@ div.luxtools-chronological-events li[data-luxtools-event] .luxtools-event-time {
margin-right: 0.25em;
}
-/* ============================================================
- * Maintenance Tasks
- * ============================================================ */
-div.luxtools-chronological-maintenance li {
- border-left-color: #e67e22;
-}
-
-li.luxtools-maintenance-task.luxtools-task-completed {
- opacity: 0.5;
- text-decoration: line-through;
-}
-
-button.luxtools-task-action,
-button.luxtools-task-complete-btn {
- margin-left: 0.5em;
- padding: 0.15em 0.5em;
- font-size: 0.85em;
- border: 1px solid @ini_border;
- border-radius: 0.2em;
- background-color: @ini_background_alt;
- cursor: pointer;
-}
-
-button.luxtools-task-action:hover,
-button.luxtools-task-complete-btn:hover {
- background-color: @ini_highlight;
-}
-
-button.luxtools-task-action:disabled,
-button.luxtools-task-complete-btn:disabled {
- opacity: 0.5;
- cursor: wait;
-}
-
-/* ============================================================
- * Maintenance Task List (syntax plugin)
- * ============================================================ */
-div.luxtools-maintenance-tasks {
- margin: 1em 0;
-}
-
-ul.luxtools-maintenance-task-list {
- list-style: none;
- padding-left: 0;
-}
-
-ul.luxtools-maintenance-task-list li {
- padding: 0.35em 0.5em;
- margin: 0.25em 0;
- border-left: 3px solid #e67e22;
-}
-
-li.luxtools-task-overdue .luxtools-task-date {
- color: #c0392b;
- font-weight: bold;
-}
-
-.luxtools-task-date {
- font-family: monospace;
- margin-right: 0.5em;
-}
-
-.luxtools-task-time {
- font-weight: bold;
- margin-right: 0.25em;
-}
-
-.luxtools-maintenance-task-item.luxtools-task-completed {
- opacity: 0.5;
- text-decoration: line-through;
-}
-
/* ============================================================
* Event Popup (content-specific styles – structural dialog
* styles live in dialog.css)
diff --git a/syntax/maintenance.php b/syntax/maintenance.php
deleted file mode 100644
index 60cbc64..0000000
--- a/syntax/maintenance.php
+++ /dev/null
@@ -1,194 +0,0 @@
-}}
- * {{maintenance_tasks>&past=14}}
- */
-class syntax_plugin_luxtools_maintenance extends SyntaxPlugin
-{
- private const DEFAULT_PAST_DAYS = 30;
-
- /** @inheritdoc */
- public function getType()
- {
- return 'substition';
- }
-
- /** @inheritdoc */
- public function getPType()
- {
- return 'block';
- }
-
- /** @inheritdoc */
- public function getSort()
- {
- return 225;
- }
-
- /** @inheritdoc */
- public function connectTo($mode)
- {
- $this->Lexer->addSpecialPattern(
- '\{\{maintenance_tasks>.*?\}\}',
- $mode,
- 'plugin_luxtools_maintenance'
- );
- }
-
- /** @inheritdoc */
- public function handle($match, $state, $pos, Doku_Handler $handler)
- {
- $match = substr($match, strlen('{{maintenance_tasks>'), -2);
- $params = $this->parseFlags($match);
-
- return [
- 'ok' => true,
- 'past' => $this->normalizePastDays($params['past'] ?? null),
- ];
- }
-
- /** @inheritdoc */
- public function render($format, Doku_Renderer $renderer, $data)
- {
- if ($data === false || !is_array($data)) return false;
- if ($format !== 'xhtml') return false;
- if (!($renderer instanceof Doku_Renderer_xhtml)) return false;
-
- $renderer->nocache();
-
- $slots = CalendarSlot::loadAll($this);
- $maintenanceSlot = $slots['maintenance'] ?? null;
-
- if ($maintenanceSlot === null || !$maintenanceSlot->isEnabled()) {
- $renderer->doc .= ''
- . '
'
- . hsc($this->getLang('maintenance_no_tasks'))
- . '
';
- return true;
- }
-
- $todayIso = date('Y-m-d');
- $pastDays = $this->normalizePastDays($data['past'] ?? null);
- $tasks = CalendarService::openMaintenanceTasks($maintenanceSlot, $todayIso, $pastDays);
- $ajaxUrl = defined('DOKU_BASE') ? (string)DOKU_BASE . 'lib/exe/ajax.php' : 'lib/exe/ajax.php';
- $secToken = function_exists('getSecurityToken') ? (string)getSecurityToken() : '';
-
- $title = (string)$this->getLang('chronological_maintenance_title');
- if ($title === '') $title = 'Tasks';
-
- $renderer->doc .= '';
- $renderer->doc .= '
' . hsc($title) . '
';
-
- if ($tasks === []) {
- $noTasks = (string)$this->getLang('maintenance_no_tasks');
- if ($noTasks === '') $noTasks = 'No open tasks.';
- $renderer->doc .= '
' . hsc($noTasks) . '
';
- } else {
- $renderer->doc .= '
';
- foreach ($tasks as $task) {
- $overdue = ($task->dateIso < $todayIso);
- $classes = 'luxtools-maintenance-task-item';
- if ($overdue) {
- $classes .= ' luxtools-task-overdue';
- }
-
- $renderer->doc .= '- doc .= ' data-uid="' . hsc($task->uid) . '"';
- $renderer->doc .= ' data-date="' . hsc($task->dateIso) . '"';
- $renderer->doc .= ' data-recurrence="' . hsc($task->recurrenceId) . '"';
- $renderer->doc .= '>';
-
- // Date badge
- $renderer->doc .= '' . hsc($task->dateIso) . ' ';
-
- // Time if not all-day
- if ($task->time !== '') {
- $renderer->doc .= '' . hsc($task->time) . ' ';
- }
-
- // Summary
- $renderer->doc .= '' . hsc($task->summary) . '';
-
- // Complete button
- $completeLabel = (string)$this->getLang('maintenance_task_complete');
- if ($completeLabel === '') $completeLabel = 'Complete';
- $renderer->doc .= ' ';
-
- $renderer->doc .= '
';
- }
- $renderer->doc .= '
';
- }
-
- $renderer->doc .= '
';
-
- return true;
- }
-
- /**
- * @param string $rawFlags
- * @return array
- */
- protected function parseFlags(string $rawFlags): array
- {
- $rawFlags = trim($rawFlags);
- if ($rawFlags === '') {
- return [];
- }
-
- if ($rawFlags[0] === '&') {
- $rawFlags = substr($rawFlags, 1);
- }
-
- $params = [];
- foreach (explode('&', $rawFlags) as $flag) {
- if (trim($flag) === '') continue;
-
- [$name, $value] = array_pad(explode('=', $flag, 2), 2, '');
- $name = strtolower(trim($name));
- $value = trim($value);
-
- if ($name === '') continue;
- $params[$name] = $value;
- }
-
- return $params;
- }
-
- /**
- * @param mixed $value
- * @return int
- */
- protected function normalizePastDays($value): int
- {
- if ($value === null || $value === '') {
- return self::DEFAULT_PAST_DAYS;
- }
-
- if (is_int($value)) {
- return max(0, $value);
- }
-
- $value = trim((string)$value);
- if ($value === '' || !preg_match('/^-?\d+$/', $value)) {
- return self::DEFAULT_PAST_DAYS;
- }
-
- return max(0, (int)$value);
- }
-}