Clean up unused syntax

This commit is contained in:
2026-01-22 20:27:47 +01:00
parent 351485efb1
commit 912f9dcac6
10 changed files with 144 additions and 241 deletions

View File

@@ -21,8 +21,7 @@ It is likely unsuited for wider adoption without modification.
luxtools provides DokuWiki syntax that:
- Lists files from configured host filesystem roots (glob pattern)
- Lists a directory's direct children (files + folders)
- Lists a directory's direct children (files + folders) or files matching a glob pattern
- Renders an image thumbnail gallery (with lightbox)
- Provides "open this folder/path" links for local workflows
- Embeds file-backed scratchpads with a minimal inline editor (no wiki revisions)
@@ -155,14 +154,23 @@ This complements DokuWiki's built-in monospace formatting (`''`) by providing qu
### 1) List files by glob pattern
The `{{directory>...}}` syntax (or `{{files>...}}` for backwards compatibility) can handle both directory listings and glob patterns. When a glob pattern is used, it renders as a table:
```
{{files>/Scape/projects/*&style=list}}
{{files>/Scape/projects/*&style=table&tableheader=1&showsize=1&showdate=1}}
{{files>/Scape/projects/*&recursive=1&sort=mtime&order=desc}}
{{directory>/Scape/projects/*}}
{{directory>/Scape/projects/*&tableheader=1&showsize=1&showdate=1}}
{{directory>/Scape/projects/*&recursive=1&sort=mtime&order=desc}}
```
Or using the legacy `files` keyword (same behavior):
```
{{files>/Scape/projects/*}}
{{files>/Scape/projects/*&tableheader=1&showsize=1&showdate=1}}
```
Notes:
- Pattern matching is performed per-directory (safe glob via fnmatch).
- Always renders as a table.
- A directory can have a title file (default: `_title.txt`) to override the displayed folder name.
### 2) List a directory (folders + files) as a table
@@ -221,7 +229,7 @@ Behaviour:
Scratchpads render the referenced file as wikitext and (when you have edit rights on the host page) provide an inline editor that saves directly to the backing file.
## Inline options reference (files/images/directory)
## Inline options reference (directory/images)
The listing syntaxes accept options appended with &key=value:
@@ -236,14 +244,7 @@ The listing syntaxes accept options appended with &key=value:
| randlinks | 0\|1 | Adds a cache-busting query parameter based on mtime. |
| showsize | 0\|1 | Show file size (where supported). |
| showdate | 0\|1 | Show last modified date (where supported). |
| listsep | ", " | Separator used in list-style rendering for extra fields. |
| maxheight | 500 | Container max-height in pixels; -1 disables scroll container. |
Additionally for `{{files>...}}`:
| Option | Values | Notes |
|---|---|---|
| style | list\|olist\|table | Output style. |
| tableheader | 0\|1 | Render table header row. |

View File

@@ -71,13 +71,14 @@ class plugin_luxtools_test extends DokuWikiTest
/**
* This function checks that all files are listed in not recursive mode.
* Uses {{files>...}} syntax for backwards compatibility (now handled by directory syntax).
*/
public function test_not_recursive()
{
global $conf;
// Render filelist
$instructions = p_get_instructions('{{files>' . TMP_DIR . '/filelistdata/*&style=list&direct=1}}');
// Render filelist using files syntax (now handled by directory plugin)
$instructions = p_get_instructions('{{files>' . TMP_DIR . '/filelistdata/*&direct=1}}');
$xhtml = p_render('xhtml', $instructions, $info);
// We should find:
@@ -91,11 +92,12 @@ class plugin_luxtools_test extends DokuWikiTest
/**
* This function checks that all files are listed in recursive mode.
* Uses {{files>...}} syntax for backwards compatibility (now handled by directory syntax).
*/
public function test_recursive()
{
// Render filelist
$instructions = p_get_instructions('{{files>' . TMP_DIR . '/filelistdata/*&style=list&direct=1&recursive=1}}');
// Render filelist using files syntax (now handled by directory plugin)
$instructions = p_get_instructions('{{files>' . TMP_DIR . '/filelistdata/*&direct=1&recursive=1}}');
$xhtml = p_render('xhtml', $instructions, $info);
// We should find:
@@ -114,54 +116,46 @@ class plugin_luxtools_test extends DokuWikiTest
}
/**
* This function checks that the unordered list mode
* generates the expected XHTML structure.
* This function checks the rendering when style=list is explicitly specified.
* Note: The files syntax is now handled by directory syntax and always renders as table.
* This test is kept for backwards compatibility testing but expects table structure.
*/
public function testUnorderedList()
{
// Render filelist
// Render filelist with explicit style=list (now ignored, renders as table)
$instructions = p_get_instructions('{{files>' . TMP_DIR . '/filelistdata/*&style=list&direct=1&recursive=1}}');
$xhtml = p_render('xhtml', $instructions, $info);
$doc = new Document();
$doc->html($xhtml);
// Now renders as a table instead of list
$structure = [
'div.luxtools-plugin' => 1,
'div.luxtools-plugin > ul' => 1,
'div.luxtools-plugin > ul > li' => 3,
'div.luxtools-plugin > ul > li:nth-child(1)' => 1,
'div.luxtools-plugin > ul > li:nth-child(1) a' => 'example.txt',
'div.luxtools-plugin > ul > li:nth-child(2) ul' => 1,
'div.luxtools-plugin > ul > li:nth-child(2) ul > li' => 1,
'div.luxtools-plugin > ul > li:nth-child(2) ul > li a' => 'example2.txt',
'div.luxtools-plugin table' => 1,
];
$this->structureCheck($doc, $structure);
}
/**
* This function checks that the ordered list mode
* generates the expected XHTML structure.
* This function checks the rendering when style=olist is explicitly specified.
* Note: The files syntax is now handled by directory syntax and always renders as table.
* This test is kept for backwards compatibility testing but expects table structure.
*/
public function testOrderedList()
{
// Render filelist
// Render filelist with explicit style=olist (now ignored, renders as table)
$instructions = p_get_instructions('{{files>' . TMP_DIR . '/filelistdata/*&style=olist&direct=1&recursive=1}}');
$xhtml = p_render('xhtml', $instructions, $info);
$doc = new Document();
$doc->html($xhtml);
// Now renders as a table instead of ordered list
$structure = [
'div.luxtools-plugin' => 1,
'div.luxtools-plugin > ol' => 1,
'div.luxtools-plugin > ol > li' => 3,
'div.luxtools-plugin > ol > li:nth-child(1)' => 1,
'div.luxtools-plugin > ol > li:nth-child(1) a' => 'example.txt',
'div.luxtools-plugin > ol > li:nth-child(2) ol' => 1,
'div.luxtools-plugin > ol > li:nth-child(2) ol > li' => 1,
'div.luxtools-plugin > ol > li:nth-child(2) ol > li a' => 'example2.txt',
'div.luxtools-plugin table' => 1,
];
$this->structureCheck($doc, $structure);

View File

@@ -15,7 +15,6 @@ class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
'extensions',
'default_sort',
'default_order',
'default_style',
'default_tableheader',
'default_foldersfirst',
'default_recursive',
@@ -25,7 +24,6 @@ class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
'default_showsize',
'default_showdate',
'default_tablecolumns',
'default_listsep',
'default_maxheight',
'thumb_placeholder',
'gallery_thumb_scale',
@@ -73,7 +71,6 @@ class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
$newConf['default_sort'] = $INPUT->str('default_sort');
$newConf['default_order'] = $INPUT->str('default_order');
$newConf['default_style'] = $INPUT->str('default_style');
$newConf['default_tableheader'] = (int)$INPUT->bool('default_tableheader');
$newConf['default_foldersfirst'] = (int)$INPUT->bool('default_foldersfirst');
$newConf['default_recursive'] = (int)$INPUT->bool('default_recursive');
@@ -83,7 +80,6 @@ class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
$newConf['default_showsize'] = (int)$INPUT->bool('default_showsize');
$newConf['default_showdate'] = (int)$INPUT->bool('default_showdate');
$newConf['default_tablecolumns'] = $INPUT->str('default_tablecolumns');
$newConf['default_listsep'] = $INPUT->str('default_listsep');
$newConf['default_maxheight'] = $INPUT->str('default_maxheight');
$newConf['thumb_placeholder'] = $INPUT->str('thumb_placeholder');
@@ -155,17 +151,6 @@ class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
echo '</select>';
echo '</label><br />';
// default_style
$defaultStyle = (string)$this->getConf('default_style');
echo '<label class="block"><span>' . hsc($this->getLang('default_style')) . '</span>';
echo '<select name="default_style" class="edit">';
foreach (['list', 'olist', 'table'] as $opt) {
$sel = ($defaultStyle === $opt) ? ' selected="selected"' : '';
echo '<option value="' . hsc($opt) . '"' . $sel . '>' . hsc($opt) . '</option>';
}
echo '</select>';
echo '</label><br />';
// default_tableheader
$checked = $this->getConf('default_tableheader') ? ' checked="checked"' : '';
echo '<label class="block"><span>' . hsc($this->getLang('default_tableheader')) . '</span> ';
@@ -218,11 +203,6 @@ class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
echo '<input type="text" class="edit" name="default_tablecolumns" value="' . hsc((string)$this->getConf('default_tablecolumns')) . '" />';
echo '</label><br />';
// default_listsep
echo '<label class="block"><span>' . hsc($this->getLang('default_listsep')) . '</span>';
echo '<input type="text" class="edit" name="default_listsep" value="' . hsc((string)$this->getConf('default_listsep')) . '" />';
echo '</label><br />';
// default_maxheight
echo '<label class="block"><span>' . hsc($this->getLang('default_maxheight')) . '</span>';
echo '<input type="number" class="edit" name="default_maxheight" value="' . hsc((string)$this->getConf('default_maxheight')) . '" />';

View File

@@ -10,10 +10,9 @@ $conf['scratchpad_paths'] = '';
$conf['defaults'] = '';
$conf['extensions'] = '';
// Listing defaults (applied to files/images/directory unless overridden inline)
// Listing defaults (applied to directory/images unless overridden inline)
$conf['default_sort'] = 'name'; // name|iname|ctime|mtime|size
$conf['default_order'] = 'asc'; // asc|desc
$conf['default_style'] = 'list'; // list|olist|table
$conf['default_tableheader'] = 0; // 0|1
$conf['default_foldersfirst'] = 0; // 0|1
$conf['default_recursive'] = 0; // 0|1
@@ -23,7 +22,6 @@ $conf['default_randlinks'] = 0; // 0|1
$conf['default_showsize'] = 0; // 0|1
$conf['default_showdate'] = 0; // 0|1
$conf['default_tablecolumns'] = 'name'; // Comma-separated: name, size, date
$conf['default_listsep'] = ', ';
$conf['default_maxheight'] = 500; // -1 disables scroll container
// MediaManager ID for gallery thumbnail placeholder

View File

@@ -16,25 +16,20 @@ class Output
/** @var array */
protected $files;
/** @var \DokuWiki_Plugin|null */
protected $plugin;
/** @var Path|false|null */
protected $openPathMapper = null;
public function __construct(\Doku_Renderer $renderer, $basedir, $webdir, $files)
public function __construct(\Doku_Renderer $renderer, $basedir, $webdir, $files, $plugin = null)
{
$this->renderer = $renderer;
$this->basedir = $basedir;
$this->webdir = $webdir;
$this->files = $files;
}
public function renderAsList($params)
{
$this->openContainer($params);
$this->renderListItems($this->files, $params);
$this->closeContainer();
$this->plugin = $plugin;
}
/**
@@ -49,8 +44,6 @@ class Output
public function renderAsGallery($params)
{
if (!($this->renderer instanceof \Doku_Renderer_xhtml)) {
$params['style'] = 'list';
$this->renderAsList($params);
return;
}
@@ -365,57 +358,6 @@ class Output
}
/**
* Recursively renders a tree of files as list items.
*
* @param array $items the files to render
* @param array $params the parameters of the filelist call
* @param int $level the level to render
* @return void
*/
protected function renderListItems($items, $params, $level = 1)
{
if ($params['style'] == 'olist') {
$this->renderer->listo_open();
} else {
$this->renderer->listu_open();
}
foreach ($items as $file) {
if ($file['children'] === false && $file['treesize'] === 0) continue; // empty directory
$this->renderer->listitem_open($level);
$this->renderer->listcontent_open();
if ($file['children'] !== false && $file['treesize'] > 0) {
// render the directory and its subtree
$this->renderer->cdata($file['name']);
$this->renderListItems($file['children'], $params, $level + 1);
} elseif ($file['children'] === false) {
// render the file link
$this->renderItemLink($file, $params['randlinks']);
// render filesize
if ($params['showsize']) {
$this->renderer->cdata($params['listsep'] . filesize_h($file['size']));
}
// render lastmodified
if ($params['showdate']) {
$this->renderer->cdata($params['listsep'] . dformat($file['mtime']));
}
}
$this->renderer->listcontent_close();
$this->renderer->listitem_close();
}
if ($params['style'] == 'olist') {
$this->renderer->listo_close();
} else {
$this->renderer->listu_close();
}
}
protected function renderItemLink($item, $cachebuster = false)
{
if (!empty($item['isdir'])) {
@@ -627,7 +569,16 @@ class Output
protected function getLang($key)
{
$syntax = plugin_load('syntax', 'luxtools');
if ($this->plugin && method_exists($this->plugin, 'getLang')) {
return $this->plugin->getLang($key);
}
// Fallback: try loading any luxtools syntax component
$syntax = plugin_load('syntax', 'luxtools_directory');
if ($syntax) {
return $syntax->getLang($key);
}
return $key; // Return key if we can't load language strings
}
}

View File

@@ -1,15 +1,15 @@
<?php
require_once(__DIR__ . '/syntax/AbstractSyntax.php');
require_once(__DIR__ . '/syntax/files.php');
require_once(__DIR__ . '/syntax/scratchpad.php');
/**
* luxtools plugin bootstrap.
*
* The actual {{files>...}} syntax implementation lives in syntax/files.php.
* The actual syntax implementation lives in the syntax classes.
* This class exists to register the syntax with DokuWiki and for other classes to have a common namespace.
*/
class syntax_plugin_luxtools extends syntax_plugin_luxtools_files
class syntax_plugin_luxtools extends syntax_plugin_luxtools_directory
{
/** @inheritdoc */
public function connectTo($mode)
@@ -18,16 +18,3 @@ class syntax_plugin_luxtools extends syntax_plugin_luxtools_files
}
}
/**
* Compatibility alias for older codebases that referenced the legacy FileTools class name.
*
* Note: plugin id/base is now `luxtools`.
*/
class syntax_plugin_filetools extends syntax_plugin_luxtools_files
{
/** @inheritdoc */
public function connectTo($mode)
{
// Intentionally empty: syntax is registered by syntax_plugin_luxtools_files.
}
}

View File

@@ -164,7 +164,6 @@ abstract class syntax_plugin_luxtools_abstract extends SyntaxPlugin
$baseDefaults = [
'sort' => (string)$this->getConf('default_sort'),
'order' => (string)$this->getConf('default_order'),
'style' => (string)$this->getConf('default_style'),
'tableheader' => (int)$this->getConf('default_tableheader'),
'foldersfirst' => (int)$this->getConf('default_foldersfirst'),
'recursive' => (int)$this->getConf('default_recursive'),
@@ -173,7 +172,6 @@ abstract class syntax_plugin_luxtools_abstract extends SyntaxPlugin
'randlinks' => (int)$this->getConf('default_randlinks'),
'showsize' => $defaultShowSize,
'showdate' => $defaultShowDate,
'listsep' => (string)$this->getConf('default_listsep'),
'maxheight' => (int)$this->getConf('default_maxheight'),
];

View File

@@ -10,6 +10,7 @@ require_once(__DIR__ . '/AbstractSyntax.php');
*
* Lists the direct children (folders and files) of a given path.
* Always renders as a table.
* Also accepts the 'files' keyword for backwards compatibility with glob patterns.
*/
class syntax_plugin_luxtools_directory extends syntax_plugin_luxtools_abstract
{
@@ -28,17 +29,81 @@ class syntax_plugin_luxtools_directory extends syntax_plugin_luxtools_abstract
return 'directory';
}
/** @inheritdoc */
public function connectTo($mode)
{
// Accept both {{directory>...}} and {{files>...}} for backwards compatibility
$this->Lexer->addSpecialPattern('\{\{directory>.+?\}\}', $mode, 'plugin_luxtools_directory');
$this->Lexer->addSpecialPattern('\{\{files>.+?\}\}', $mode, 'plugin_luxtools_directory');
}
/** @inheritdoc */
public function handle($match, $state, $pos, Doku_Handler $handler)
{
// Detect which keyword was used
$keyword = 'directory';
if (str_starts_with($match, '{{files>')) {
$keyword = 'files';
}
$match = substr($match, strlen('{{' . $keyword . '>'), -2);
[$path, $flags] = array_pad(explode('&', $match, 2), 2, '');
$params = $this->parseFlags($flags);
$pathData = $this->processPath($path);
// Store the original keyword to determine processing mode
$pathData['isGlobPattern'] = ($keyword === 'files');
return ['pathData' => $pathData, 'params' => $params];
}
/** @inheritdoc */
protected function processPath(string $path): array
{
// Directory path (no glob/pattern)
// Check if path contains glob characters (*, ?, [, ])
$hasGlob = (str_contains($path, '*') || str_contains($path, '?') ||
str_contains($path, '[') || str_contains($path, ']'));
if ($hasGlob) {
// Process as glob pattern (old files syntax)
[$base, $pattern] = $this->separatePathAndPattern($path);
return ['base' => $base, 'pattern' => $pattern, 'isGlobPattern' => true];
} else {
// Process as directory path
$path = Path::cleanPath($path, true);
return ['path' => $path];
return ['path' => $path, 'isGlobPattern' => false];
}
}
/** @inheritdoc */
protected function doRender(string $format, \Doku_Renderer $renderer, array $pathData, array $params): bool
{
$isGlobPattern = $pathData['isGlobPattern'] ?? false;
if ($isGlobPattern && isset($pathData['base'], $pathData['pattern'])) {
// Old files syntax behavior: crawl with glob pattern
$pathInfo = $this->getPathInfoSafe($pathData['base'], $renderer);
if ($pathInfo === false) {
return true;
}
$crawler = $this->createCrawler($params);
$result = $crawler->crawl(
$pathInfo['root'],
$pathInfo['local'],
$pathData['pattern'],
$params['recursive'],
$params['titlefile']
);
// Pass the base directory as openlocation so the "Open Location" link is displayed.
$params['openlocation'] = $pathInfo['root'] . $pathInfo['local'];
$output = new Output($renderer, $pathInfo['root'], $pathInfo['web'], $result, $this);
$output->renderAsTable($params);
} else {
// Normal directory listing behavior
$pathInfo = $this->getPathInfoSafe($pathData['path'], $renderer);
if ($pathInfo === false) {
return true;
@@ -54,12 +119,11 @@ class syntax_plugin_luxtools_directory extends syntax_plugin_luxtools_abstract
$params['titlefile']
);
// Always render as table style
$params['style'] = 'table';
// Render the table even if empty so the "Open Location" link is displayed.
$output = new Output($renderer, $pathInfo['root'], $pathInfo['web'], $items);
$output = new Output($renderer, $pathInfo['root'], $pathInfo['web'], $items, $this);
$output->renderAsFlatTable($params);
}
return true;
}
}

View File

@@ -1,62 +0,0 @@
<?php
use dokuwiki\plugin\luxtools\Output;
require_once(__DIR__ . '/AbstractSyntax.php');
/**
* luxtools Plugin: Files syntax.
*
* Lists files matching a given glob pattern.
*/
class syntax_plugin_luxtools_files extends syntax_plugin_luxtools_abstract
{
/** @inheritdoc */
protected function getSyntaxKeyword(): string
{
return 'files';
}
/** @inheritdoc */
protected function processPath(string $path): array
{
[$base, $pattern] = $this->separatePathAndPattern($path);
return ['base' => $base, 'pattern' => $pattern];
}
/** @inheritdoc */
protected function doRender(string $format, \Doku_Renderer $renderer, array $pathData, array $params): bool
{
$pathInfo = $this->getPathInfoSafe($pathData['base'], $renderer);
if ($pathInfo === false) {
return true;
}
$crawler = $this->createCrawler($params);
$result = $crawler->crawl(
$pathInfo['root'],
$pathInfo['local'],
$pathData['pattern'],
$params['recursive'],
$params['titlefile']
);
// For table style, pass the base directory as openlocation so the "Open Location" link is displayed.
if ($params['style'] === 'table') {
$params['openlocation'] = $pathInfo['root'] . $pathInfo['local'];
}
$output = new Output($renderer, $pathInfo['root'], $pathInfo['web'], $result);
switch ($params['style']) {
case 'list':
case 'olist':
$output->renderAsList($params);
break;
case 'table':
$output->renderAsTable($params);
break;
}
return true;
}
}

View File

@@ -22,11 +22,9 @@ class syntax_plugin_luxtools_images extends syntax_plugin_luxtools_abstract
{
// Images syntax doesn't use some of the common params
return [
'style' => null,
'tableheader' => null,
'showsize' => null,
'showdate' => null,
'listsep' => null,
];
}
@@ -62,19 +60,13 @@ class syntax_plugin_luxtools_images extends syntax_plugin_luxtools_abstract
return true;
}
$output = new Output($renderer, $pathInfo['root'], $pathInfo['web'], $items);
if ($format == 'xhtml') {
$output->renderAsGallery($params);
return true;
// Images syntax only supports XHTML format (gallery rendering)
if ($format !== 'xhtml') {
return false;
}
// Fallback for non-XHTML formats: render as a list of links
$params['style'] = 'list';
$params['showsize'] = 0;
$params['showdate'] = 0;
$params['listsep'] = ', ';
$output->renderAsList($params);
$output = new Output($renderer, $pathInfo['root'], $pathInfo['web'], $items, $this);
$output->renderAsGallery($params);
return true;
}