# luxtools (DokuWiki plugin) luxtools is a suite of tools designed to integrate the host file system with DokuWiki, intentionally sidestepping the built-in MediaManager for specific workflows. This is a personal project that models my specific workflows and preferences. It is likely unsuited for wider adoption without modification. ## Related projects - luxtools-client: https://git.luxick.de/luxick/luxtools-client A client application for direct integration with the client machine (e.g. opening folders/paths from within the browser). - luxtools-template: https://git.luxick.de/luxick/luxtools-template A DokuWiki template designed to complement the features of this plugin. ## What this plugin does luxtools provides DokuWiki syntax that: - Lists a directory's direct children (files + folders) or files matching a glob pattern - Renders an image thumbnail gallery (with lightbox) - Groups multiple `{{image>...}}` blocks in compact grid/flex layouts - Provides "open this folder/path" links for local workflows - Embeds file-backed scratchpads with a minimal inline editor (no wiki revisions) - Links a page to a media folder via a UUID (.pagelink), enabling a `blobs/` alias - Adds a Page ID download link in the page info area to fetch a `.pagelink` file - Renders a basic calendar widget with clickable day links to chronological pages It also ships a small file-serving endpoint (`lib/plugins/luxtools/file.php`) used to deliver files and generate cached thumbnails. ## Note on security The file-serving endpoint (`lib/plugins/luxtools/file.php`) runs inside DokuWiki and enforces access via per-page ACL: the requester must have at least read access to the wiki page that rendered the link. ## Installation Install like any other DokuWiki plugin. If you install this plugin manually, make sure it is installed in: `lib/plugins/luxtools/` If the folder is called differently, DokuWiki will not load it. This plugin uses Composer dependencies shipped inside `vendor/`. If dependencies are missing in your local checkout, run: ```bash php composer.phar install ``` ## Project structure (developer notes) This repository follows DokuWiki's plugin conventions at the top level (e.g. `syntax.php`, `conf/`, `lang/`, endpoints like `file.php`). Reusable PHP code lives in `src/` and is loaded via `autoload.php`. When adding new internal classes under the `dokuwiki\plugin\luxtools\` namespace, place them in `src/.php`. JavaScript is split into small modules under `js/` and registered via `action.php` so DokuWiki loads them in order. ## IDE support (developer notes) This plugin extends and uses DokuWiki core classes (for example `dokuwiki\Extension\ActionPlugin`, `dokuwiki\Extension\SyntaxPlugin`, renderers, handlers). If you only open the plugin folder in your IDE, those types may show as “unknown”. DokuWiki does not currently ship an official PHP “SDK”/stub package for IDEs. The most reliable way to get full type navigation and autocomplete is to have the DokuWiki sources available in your workspace. Two recommended setups: ### Option A: Add DokuWiki as a git submodule (recommended for a single-folder workspace) From the plugin root: ```bash git submodule add https://github.com/dokuwiki/dokuwiki.git _dokuwiki git submodule update --init --recursive ``` The repository includes a VS Code config in `.vscode/settings.json` that points Intelephense at `./_dokuwiki/*` so the classes resolve. `deploy.sh` excludes `_dokuwiki/` to avoid deploying the dev-only checkout. ### Option B: Use a separate DokuWiki checkout next to the plugin (recommended if you don’t want submodules) - Clone DokuWiki into a sibling folder (outside this repo) - Open a multi-root VS Code workspace with both folders This avoids changing the git state of the plugin repo, but still gives the IDE access to DokuWiki’s class definitions. ## Configuration luxtools is configured via its dedicated admin page: `Admin -> Additional Plugins -> luxtools` Key settings: - **paths** Allowed base filesystem roots (one per line). Each root can be followed by: - `A> Alias` (optional) alias used in wiki syntax and open links Example: ``` /srv/share/Datascape/ A> Scape ``` Notes: - Wiki syntax accepts aliases in path form (for example `Scape/sub/folder`). - Open links sent to the local client service are emitted as `Alias>relative/path` (for example `Scape>sub/folder`) so each client can resolve its own local root. luxtools links use the plugin endpoint: `lib/plugins/luxtools/file.php?root=...&file=...` The generated URLs also include the current wiki page id (`id=...`) so `file.php` can enforce ACLs for the host page. - **scratchpad_paths** Scratchpad file map (one file path per line, followed by an `A>` alias line). Example: ``` /var/lib/dokuwiki-scratchpads/startpad.txt A> start ``` - **defaults** Default inline options appended to each listing call. - **extensions** Comma-separated list of file extensions allowed in listings. Leave empty to allow all. - **thumb_placeholder** MediaManager ID used as a placeholder image in the gallery (optional). - **gallery_thumb_scale** Multiplier for generated thumbnails (1 = 150x150, 2 = 300x300), while still displaying them as 150x150. Useful for HiDPI screens. - **open_service_url** URL of a local client service used by `{{open>...}}` and directory links. See luxtools-client. - **image_base_path** Base filesystem path used for chronological photo integration. On canonical day pages (`chronological:YYYY:MM:DD`), files that start with `YYYY-MM-DD` are listed automatically. If a yearly subfolder exists (for example `.../2026/`), it is preferred. - **calendar_ics_files** Local calendar `.ics` files (one absolute file path per line). Events are parsed by `sabre/vobject` and shown on matching chronological day pages. Recurrence and exclusions from the ICS are respected. For timed entries, the page stores the original timestamp and renders the visible time in the browser's local timezone. Multi-day events appear on each overlapping day. - **pagelink_search_depth** Maximum directory depth for `.pagelink` discovery under each configured root. `0` means only the root directory itself is checked. ### Template style settings The `{{open>...}}` links and directory “open” links use a dedicated color placeholder so they can be customized in **Template Style Settings**. - **Location Links** (`__luxtools_locationlink__`) Default: `#b57d35` To be able to customize the color via the UI add the following to your local template style file at `conf/tpl//style.ini` under the `[replacements]` section: ``` __luxtools_locationlink__ = "#b57d35" ; @ini_luxtools_locationlink ``` ### Temporary global input styling Because the target template is not ready yet, the plugin currently ships a temporary stylesheet that applies `@ini_text`, `@ini_background`, and `@ini_border` to all `input`, `textarea`, and `select` elements site-wide. This file is explicitly marked as a temporary fix and should be removed once the template provides proper form control styles. Temporary file: [temp-input-colors.css](temp-input-colors.css) Developer note: DokuWiki serves a combined stylesheet via `lib/exe/css.php` and caches it. Cache invalidation is based on the mtimes of the source CSS/LESS files. If you deploy into a mounted/remote filesystem with a different clock, preserving mtimes can prevent automatic invalidation (making it look like your CSS changes don't load until you purge cache). `deploy.sh` avoids preserving mtimes by default to make CSS iteration smoother. If you explicitly want to preserve mtimes, use: ```bash ./deploy.sh --preserve-times ``` ## Features and usage ### 0) Editor toolbar: Code block button The plugin adds a custom button to the DokuWiki editor toolbar for quickly inserting `` blocks. When editing a page, click the code block button (angle brackets icon `<>`) in the toolbar to wrap selected text in `` tags, or to insert an empty code block at the cursor position. This complements DokuWiki's built-in monospace formatting (`''`) by providing quick access to HTML code blocks. ### 0.1) Editor toolbar: Date Fix The plugin adds two toolbar buttons for normalizing timestamps while editing: - **Date Fix**: Converts the selected timestamp to `YYYY-MM-DD` (or `YYYY-MM-DD HH:MM:SS` if time is included). - **Date Fix (All)**: Scans the whole page and normalizes any recognizable timestamps. Supported input examples include: - `2026-01-30` - `30.01.2026` - `30 Jan 2026` - `Jan 30, 2026` - `2026-01-30 13:45` - `2026-01-30T13:45:00` ### 0.2) Page Link: link a page to a folder Page linking uses a page-scoped UUID stored in page metadata. This UUID is used to link the page to a folder that contains a `.pagelink` file with the same UUID. The Page Link workflow is driven by the **Page ID link** in the page info area (page footer, `.docInfo`): 1. **Link Page** (page has no UUID yet) Creates the UUID and downloads a `.pagelink` file. 2. **Download Link File** (page has UUID, but no linked folder found) Downloads the `.pagelink` file. 3. **Unlink Page** (page is linked) Prompts for confirmation, removes the `.pagelink` file from the linked folder (if found), removes the UUID from the page, and refreshes the page. After downloading the `.pagelink` file, place it into the folder you want to link (within your configured `paths` roots). Once DokuWiki can discover it, the page becomes “linked”. Once linked, you can use `blobs/` as an alias in luxtools syntax on that page, for example: ``` {{images>blobs/*.png}} {{directory>blobs/&recursive=1}} ``` ### 0.3) Calendar widget Render a basic monthly calendar that links each day to canonical chronological pages: ``` {{calendar>}} {{calendar>2024-10}} ``` Notes: - `{{calendar>}}` renders the current month. - `{{calendar>YYYY-MM}}` renders a specific month. - Day links target `chronological:YYYY:MM:DD`. - Header month/year links target `chronological:YYYY:MM` and `chronological:YYYY`. - Prev/next month buttons update the widget in-place without a full page reload. - Month switches fetch server-rendered widget HTML via AJAX and replace only the widget node. ### 0.4) Virtual chronological day pages When a canonical day page (for example `chronological:2026:02:13`) does not yet exist, luxtools renders a virtual page in normal show mode instead of the default "page does not exist" output. The virtual page includes: - a German-formatted heading (for example `Freitag, 13. Februar 2026`) - matching local calendar events from configured `.ics` files (when available) - matching day photos (via existing `{{images>...}}` rendering) when available The page is only created once you edit and save actual content. ### 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: ``` {{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 ``` {{directory>/Scape/projects/&tableheader=1&foldersfirst=1&sort=name}} ``` This always renders as a table. It includes an "Open Location" link above the table when rendered as XHTML. ### 3) Image gallery with thumbnails + lightbox ``` {{images>/Scape/photos/2025/*}} {{images>/Scape/photos/2025/*&recursive=1}} ``` Clicking a thumbnail opens a lightbox viewer. Thumbnails are generated and cached via the plugin endpoint. ### 4) Single image with caption (imagebox) ``` {{image>/Scape/photos/picture.jpg|This is the caption}} {{image>/Scape/photos/picture.jpg|Caption|400}} {{image>/Scape/photos/picture.jpg|Caption|400x300}} {{image>/Scape/photos/picture.jpg|Caption|left}} {{image>/Scape/photos/picture.jpg|Caption|400¢er}} {{image>https://example.com/images/picture.jpg|Remote image caption}} {{image>https://example.com/images/picture.jpg|Remote caption|400x300&left}} ``` Renders a Wikipedia-style image box with optional caption. The syntax uses pipe-separated parts: - `{{image>path|caption}}` – Image with caption (uses defaults) - `{{image>path|caption|options}}` – Image with caption and options Options (in the third part, separated by `&`): - Size: `200` (width) or `200x150` (width × height) - Alignment: `left`, `right` (default), or `center` - Combined: `400&left` or `400x300¢er` The image links to the full-size version when clicked. Remote images (HTTP/HTTPS URLs) are linked directly without proxying or thumbnailing. ### 5) Group multiple image boxes compactly Use ` ... ` to arrange multiple `{{image>...}}` entries in less vertical space. ```text {{image>/Scape/photos/1.jpg|One|300}} {{image>/Scape/photos/2.jpg|Two|300}} {{image>/Scape/photos/3.jpg|Three|300}} {{image>/Scape/photos/4.jpg|Four|300}} {{image>/Scape/photos/1.jpg|One|220}} {{image>/Scape/photos/2.jpg|Two|220}} {{image>/Scape/photos/3.jpg|Three|220}} {{image>/Scape/photos/1.jpg|One|260}} {{image>/Scape/photos/2.jpg|Two|260}} {{image>/Scape/photos/3.jpg|Three|260}} {{image>/Scape/photos/1.jpg|One|220}} {{image>/Scape/photos/2.jpg|Two|220}} {{image>/Scape/photos/3.jpg|Three|220}} ``` Supported attributes on the opening tag: - `layout`: `flex` (default) or `grid` - `cols`: integer >= 1 (default `2`, used by `grid`) - `gap`: CSS length token such as `0`, `0.6rem`, `8px` (default `0`) - `justify`: `start`, `center`, `end`, `space-between`, `space-around`, `space-evenly` (default `start`) - `align`: `start`, `center`, `end`, `stretch`, `baseline` (default `start`) Notes: - The wrapper only controls layout. It adds no own border/background/frame. - Invalid values silently fall back to defaults. - Unknown attributes render a small warning string, e.g. `[grouping: unknown option(s): gpa]`. - Existing standalone `{{image>...}}` behavior is unchanged outside ``. ### 6) Open a local path/folder (best-effort) ``` {{open>/Scape/projects|Open projects folder}} {{open>/home/me/notes|Open local folder}} {{open>file:///home/me/notes|Open via file://}} ``` Behaviour: - Prefer calling the configured local client service (open_service_url). - Fall back to opening a file:// URL in a new tab (often blocked by browsers). ### 7) Scratchpads (shared, file-backed, no page revisions) ``` {{scratchpad>start}} ``` 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. ### 8) Link Favicons (automatic) External links automatically display the favicon of the linked website. This feature: - Uses DuckDuckGo's favicon service (`icons.duckduckgo.com`) - Works on all external links (class `urlextern`) - Shows grayscale icons that become colored on hover - Browser handles caching; no server-side storage needed No configuration required. The feature is enabled by default for all external links. Based on the [linkfavicon plugin](https://github.com/shaoyanmin/linkfavicon) by Shao Yanmin. ## Inline options reference (directory/images) The listing syntaxes accept options appended with &key=value: | Option | Values | Notes | |---|---|---| | recursive | 0\|1 | Recurse into subdirectories. | | sort | name\|iname\|ctime\|mtime\|size | Sort key. | | order | asc\|desc | Sort order. | | foldersfirst | 0\|1 | Group folders before files (useful for tables). | | titlefile | _title.txt | Directory title override file name. | | cache | 0\|1 | 0 disables page caching (default). | | 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). | | maxheight | 500 | Container max-height in pixels; -1 disables scroll container. | | tableheader | 0\|1 | Render table header row. | ## Admin settings The admin settings page includes a **default_tablecolumns** option that lets you specify which columns are displayed by default in table-style listings. This is a comma-separated list of column names: - `name` – File/folder name (always shown) - `size` – File size - `date` – Last modified date Example: `name,size,date` shows all columns by default. ## Credits / upstream luxtools is a fork of the [DokuWiki Filelist plugin](https://www.dokuwiki.org/plugin:filelist). Upstream authors and contributors include Gina Häußge and the DokuWiki community (Dokufreaks). This fork keeps the original license (GPL-2) and retains the relevant copyright notices in the source. ## Development helpers - Linux/macOS: ./deploy.sh ## License GPL-2. See COPYING / LICENSE.