195 lines
6.0 KiB
PHP
195 lines
6.0 KiB
PHP
<?php
|
|
|
|
use dokuwiki\Extension\SyntaxPlugin;
|
|
use dokuwiki\plugin\luxtools\CalendarService;
|
|
use dokuwiki\plugin\luxtools\CalendarSlot;
|
|
|
|
require_once(__DIR__ . '/../autoload.php');
|
|
|
|
/**
|
|
* luxtools Plugin: Maintenance task list syntax.
|
|
*
|
|
* Renders a list of all non-completed maintenance tasks due today or earlier.
|
|
*
|
|
* Syntax:
|
|
* {{maintenance_tasks>}}
|
|
* {{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 .= '<div class="luxtools-plugin luxtools-maintenance-tasks">'
|
|
. '<p class="luxtools-empty">'
|
|
. hsc($this->getLang('maintenance_no_tasks'))
|
|
. '</p></div>';
|
|
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 .= '<div class="luxtools-plugin luxtools-maintenance-tasks"'
|
|
. ' data-luxtools-ajax-url="' . hsc($ajaxUrl) . '"'
|
|
. ' data-luxtools-sectok="' . hsc($secToken) . '">';
|
|
$renderer->doc .= '<h3>' . hsc($title) . '</h3>';
|
|
|
|
if ($tasks === []) {
|
|
$noTasks = (string)$this->getLang('maintenance_no_tasks');
|
|
if ($noTasks === '') $noTasks = 'No open tasks.';
|
|
$renderer->doc .= '<p class="luxtools-empty">' . hsc($noTasks) . '</p>';
|
|
} else {
|
|
$renderer->doc .= '<ul class="luxtools-maintenance-task-list">';
|
|
foreach ($tasks as $task) {
|
|
$overdue = ($task->dateIso < $todayIso);
|
|
$classes = 'luxtools-maintenance-task-item';
|
|
if ($overdue) {
|
|
$classes .= ' luxtools-task-overdue';
|
|
}
|
|
|
|
$renderer->doc .= '<li class="' . $classes . '"';
|
|
$renderer->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 .= '<span class="luxtools-task-date">' . hsc($task->dateIso) . '</span> ';
|
|
|
|
// Time if not all-day
|
|
if ($task->time !== '') {
|
|
$renderer->doc .= '<span class="luxtools-task-time">' . hsc($task->time) . '</span> ';
|
|
}
|
|
|
|
// Summary
|
|
$renderer->doc .= '<span class="luxtools-task-summary">' . hsc($task->summary) . '</span>';
|
|
|
|
// Complete button
|
|
$completeLabel = (string)$this->getLang('maintenance_task_complete');
|
|
if ($completeLabel === '') $completeLabel = 'Complete';
|
|
$renderer->doc .= ' <button class="luxtools-task-complete-btn" type="button"'
|
|
. ' data-action="complete"'
|
|
. '>' . hsc($completeLabel) . '</button>';
|
|
|
|
$renderer->doc .= '</li>';
|
|
}
|
|
$renderer->doc .= '</ul>';
|
|
}
|
|
|
|
$renderer->doc .= '</div>';
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @param string $rawFlags
|
|
* @return array<string,string>
|
|
*/
|
|
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);
|
|
}
|
|
}
|