getSyntaxKeyword(); $pattern = '\{\{' . $keyword . '>.+?\}\}'; $this->Lexer->addSpecialPattern($pattern, $mode, 'plugin_luxtools_' . $keyword); } /** @inheritdoc */ public function handle($match, $state, $pos, Doku_Handler $handler) { global $INPUT; // Do not allow the syntax in discussion plugin comments if (!$this->getConf('allow_in_comments') && $INPUT->has('comment')) { return false; } $keyword = $this->getSyntaxKeyword(); $match = substr($match, strlen('{{' . $keyword . '>'), -2); [$path, $flags] = array_pad(explode('&', $match, 2), 2, ''); $params = $this->parseFlags($flags); $pathData = $this->processPath($path); return ['pathData' => $pathData, 'params' => $params]; } /** @inheritdoc */ public function render($format, Doku_Renderer $renderer, $data) { if ($data === false) { return false; } if ($format !== 'xhtml' && $format !== 'odt') { return false; } $pathData = $data['pathData']; $params = $data['params']; // Disable caching if requested if ($params['cache'] === 0) { $renderer->nocache(); } return $this->doRender($format, $renderer, $pathData, $params); } /** * Parse flags string into parameters array. * * @param string $flags The flags string from the syntax * @return array Parsed parameters */ protected function parseFlags(string $flags): array { // Base defaults shared by all handlers $baseDefaults = [ 'sort' => 'name', 'order' => 'asc', 'style' => 'list', 'tableheader' => 0, 'recursive' => 0, 'titlefile' => '_title.txt', 'cache' => 0, 'randlinks' => 0, 'showsize' => 0, 'showdate' => 0, 'listsep' => ', ', 'maxheight' => 500, ]; // Merge with handler-specific defaults $params = array_merge($baseDefaults, $this->getDefaultParams()); // Load default config options and combine with provided flags $flags = $this->getConf('defaults') . '&' . $flags; $flagList = explode('&', $flags); foreach ($flagList as $flag) { if (empty(trim($flag))) { continue; } [$name, $value] = sexplode('=', $flag, 2, ''); $params[trim($name)] = trim(trim($value), '"'); // quotes can be used to keep whitespace } return $params; } /** * Get path info with error handling. * * @param string $basePath The base path to resolve * @param \Doku_Renderer $renderer The renderer for error output * @return array|false Path info array or false on error */ protected function getPathInfoSafe(string $basePath, \Doku_Renderer $renderer) { try { $pathHelper = new Path($this->getConf('paths')); return $pathHelper->getPathInfo($basePath); } catch (\Exception $e) { $this->renderError($renderer, 'error_outsidejail'); return false; } } /** * Create and configure a Crawler instance. * * @param array $params The parameters array * @return Crawler */ protected function createCrawler(array $params): Crawler { $crawler = new Crawler($this->getConf('extensions')); $crawler->setSortBy($params['sort']); $crawler->setSortReverse($params['order'] === 'desc'); return $crawler; } /** * Render an error message. * * @param \Doku_Renderer $renderer The renderer * @param string $langKey The language key for the error message */ protected function renderError(\Doku_Renderer $renderer, string $langKey): void { $renderer->cdata('[n/a: ' . $this->getLang($langKey) . ']'); } /** * Separate a path into base directory and pattern. * * @param string $path The full path with pattern * @return array [base, pattern] */ protected function separatePathAndPattern(string $path): array { $path = Path::cleanPath($path, false); $parts = explode('/', $path); $pattern = array_pop($parts); $base = implode('/', $parts) . '/'; return [$base, $pattern]; } }