Add single image display.
This commit is contained in:
33
README.md
33
README.md
@@ -174,7 +174,25 @@ This always renders as a table. It includes an "Open Location" link above the ta
|
||||
|
||||
Clicking a thumbnail opens a lightbox viewer. Thumbnails are generated and cached via the plugin endpoint.
|
||||
|
||||
### 4) Open a local path/folder (best-effort)
|
||||
### 4) Single image with caption (imagebox)
|
||||
|
||||
```
|
||||
{{image>/Scape/photos/picture.jpg|This is the caption}}
|
||||
{{image>/Scape/photos/picture.jpg?400|Resized to 400px width}}
|
||||
{{image>/Scape/photos/picture.jpg?400x300|Fixed dimensions}}
|
||||
{{image>/Scape/photos/picture.jpg?left|Float left}}
|
||||
{{image>/Scape/photos/picture.jpg?400¢er|Resized and centered}}
|
||||
```
|
||||
|
||||
Renders a Wikipedia-style image box with optional caption. Parameters after `?` are 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.
|
||||
|
||||
### 5) Open a local path/folder (best-effort)
|
||||
|
||||
```
|
||||
{{open>/Scape/projects|Open projects folder}}
|
||||
@@ -186,7 +204,7 @@ 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).
|
||||
|
||||
### 5) Scratchpads (shared, file-backed, no page revisions)
|
||||
### 6) Scratchpads (shared, file-backed, no page revisions)
|
||||
|
||||
```
|
||||
{{scratchpad>start}}
|
||||
@@ -221,6 +239,17 @@ Additionally for `{{files>...}}`:
|
||||
| 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).
|
||||
|
||||
@@ -12,7 +12,6 @@ class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
|
||||
protected $configKeys = [
|
||||
'paths',
|
||||
'scratchpad_paths',
|
||||
'allow_in_comments',
|
||||
'extensions',
|
||||
'default_sort',
|
||||
'default_order',
|
||||
@@ -25,6 +24,7 @@ class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
|
||||
'default_randlinks',
|
||||
'default_showsize',
|
||||
'default_showdate',
|
||||
'default_tablecolumns',
|
||||
'default_listsep',
|
||||
'default_maxheight',
|
||||
'thumb_placeholder',
|
||||
@@ -69,7 +69,6 @@ class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
|
||||
$scratchpadPaths = str_replace(["\r\n", "\r"], "\n", $scratchpadPaths);
|
||||
$newConf['scratchpad_paths'] = $scratchpadPaths;
|
||||
|
||||
$newConf['allow_in_comments'] = (int)$INPUT->bool('allow_in_comments');
|
||||
$newConf['extensions'] = $INPUT->str('extensions');
|
||||
|
||||
$newConf['default_sort'] = $INPUT->str('default_sort');
|
||||
@@ -83,6 +82,7 @@ class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
|
||||
$newConf['default_randlinks'] = (int)$INPUT->bool('default_randlinks');
|
||||
$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');
|
||||
|
||||
@@ -126,12 +126,6 @@ class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
|
||||
echo '<textarea name="scratchpad_paths" rows="6" cols="80" class="edit">' . hsc($scratchpadPaths) . '</textarea>';
|
||||
echo '</label><br />';
|
||||
|
||||
// allow_in_comments
|
||||
$checked = $this->getConf('allow_in_comments') ? ' checked="checked"' : '';
|
||||
echo '<label class="block"><span>' . hsc($this->getLang('allow_in_comments')) . '</span> ';
|
||||
echo '<input type="checkbox" name="allow_in_comments" value="1"' . $checked . ' />';
|
||||
echo '</label><br />';
|
||||
|
||||
// extensions
|
||||
echo '<label class="block"><span>' . hsc($this->getLang('extensions')) . '</span> ';
|
||||
echo '<input type="text" class="edit" name="extensions" value="' . hsc((string)$this->getConf('extensions')) . '" />';
|
||||
@@ -219,6 +213,11 @@ class admin_plugin_luxtools_main extends DokuWiki_Admin_Plugin
|
||||
echo '<input type="checkbox" name="default_showdate" value="1"' . $checked . ' />';
|
||||
echo '</label><br />';
|
||||
|
||||
// default_tablecolumns
|
||||
echo '<label class="block"><span>' . hsc($this->getLang('default_tablecolumns')) . '</span>';
|
||||
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')) . '" />';
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
$conf['paths'] = '';
|
||||
$conf['scratchpad_paths'] = '';
|
||||
$conf['allow_in_comments'] = 0;
|
||||
// Legacy (advanced): additional default flags in the same syntax as inline options.
|
||||
$conf['defaults'] = '';
|
||||
$conf['extensions'] = '';
|
||||
@@ -23,6 +22,7 @@ $conf['default_cache'] = 0; // 0|1
|
||||
$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
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ $lang['err_security'] = 'Sicherheits-Token ungültig. Bitte erneut versuchen.';
|
||||
|
||||
$lang['paths'] = 'Erlaubte Basis-Pfade (eine pro Zeile). Optional: Pfad mit A>-Alias ergaenzen.';
|
||||
$lang['scratchpad_paths'] = 'Scratchpad-Dateien (eine pro Zeile). Jeder Dateipfad muss eine Erweiterung enthalten. Mit einer folgenden A>-Zeile wird der Pad-Name gesetzt, der im Wiki verwendet wird.';
|
||||
$lang['allow_in_comments'] = 'luxtools-Syntax (files/images/directory/scratchpad) in Kommentaren erlauben.';
|
||||
$lang['extensions'] = 'Kommagetrennte Liste erlaubter Dateiendungen.';
|
||||
|
||||
$lang['listing_defaults'] = 'Listen-Standardwerte';
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
$lang["paths"] = "Erlaubte Basis-Pfade (eine pro Zeile). Optional: Pfad mit A>-Alias ergaenzen.";
|
||||
$lang["scratchpad_paths"] = "Scratchpad-Dateien (eine pro Zeile). Jeder Dateipfad muss eine Erweiterung enthalten. Mit einer folgenden A>-Zeile wird der Pad-Name gesetzt, der im Wiki verwendet wird.";
|
||||
$lang["allow_in_comments"] = "luxtools-Syntax (files/images/directory/scratchpad) in Kommentaren erlauben.";
|
||||
$lang["extensions"] = "Kommagetrennte Liste erlaubter Dateiendungen.";
|
||||
|
||||
$lang["listing_defaults"] = "Listen-Standardwerte";
|
||||
|
||||
@@ -28,7 +28,6 @@ $lang['err_security'] = 'Security token mismatch. Please retry.';
|
||||
|
||||
$lang['paths'] = 'Allowed base paths (one per line). Optional: follow a path with A> alias.';
|
||||
$lang['scratchpad_paths'] = 'Scratchpad files (one per line). Each file path must include the extension. Use a following A> line to set the pad name used in the wiki.';
|
||||
$lang['allow_in_comments'] = 'Whether to allow luxtools syntax (files/images/directory/scratchpad) to be used in comments.';
|
||||
$lang['extensions'] = 'Comma-separated list of allowed file extensions to list.';
|
||||
|
||||
$lang['listing_defaults'] = 'Listing defaults';
|
||||
@@ -43,6 +42,7 @@ $lang['default_cache'] = 'Enable page caching by default (0 disables caching).';
|
||||
$lang['default_randlinks'] = 'Add cache-busting query parameter based on mtime by default.';
|
||||
$lang['default_showsize'] = 'Show file size by default (where supported).';
|
||||
$lang['default_showdate'] = 'Show last modified date by default (where supported).';
|
||||
$lang['default_tablecolumns'] = 'Default table columns (comma-separated). Available: name, size, date. Example: "name,size,date" shows all columns.';
|
||||
$lang['default_listsep'] = 'Default separator used in list-style rendering (e.g. ", ").';
|
||||
$lang['default_maxheight'] = 'Default max-height in px for scroll container (-1 disables).';
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
$lang['paths'] = 'Allowed base paths (one per line). Optional: follow a path with A> alias.';
|
||||
$lang['scratchpad_paths'] = 'Scratchpad files (one per line). Each file path must include the extension; use a following A> line to set the pad name used in the wiki.';
|
||||
$lang['allow_in_comments'] = 'Whether to allow luxtools syntax (files/images/directory/scratchpad) to be used in comments.';
|
||||
$lang['extensions'] = 'Comma-separated list of allowed file extensions to list';
|
||||
|
||||
$lang['listing_defaults'] = 'Listing defaults';
|
||||
|
||||
@@ -341,29 +341,43 @@ class Output
|
||||
}
|
||||
|
||||
$renderer->tabletbody_open();
|
||||
foreach ($items as $item) {
|
||||
|
||||
if ($items === []) {
|
||||
// Render a single row with an empty state message.
|
||||
$renderer->tablerow_open();
|
||||
$renderer->tablecell_open();
|
||||
$this->renderItemLink($item, $params['randlinks']);
|
||||
$renderer->tablecell_open($columns);
|
||||
if ($renderer instanceof \Doku_Renderer_xhtml) {
|
||||
$renderer->doc .= '<span class="luxtools-empty">' . hsc($this->getLang('empty_files')) . '</span>';
|
||||
} else {
|
||||
$renderer->cdata($this->getLang('empty_files'));
|
||||
}
|
||||
$renderer->tablecell_close();
|
||||
|
||||
if ($params['showsize']) {
|
||||
$renderer->tablecell_open(1, 'right');
|
||||
if (!empty($item['isdir'])) {
|
||||
$renderer->cdata('');
|
||||
} else {
|
||||
$renderer->cdata(filesize_h($item['size']));
|
||||
}
|
||||
$renderer->tablecell_close();
|
||||
}
|
||||
|
||||
if ($params['showdate']) {
|
||||
$renderer->tablecell_open();
|
||||
$renderer->cdata(dformat($item['mtime']));
|
||||
$renderer->tablecell_close();
|
||||
}
|
||||
|
||||
$renderer->tablerow_close();
|
||||
} else {
|
||||
foreach ($items as $item) {
|
||||
$renderer->tablerow_open();
|
||||
$renderer->tablecell_open();
|
||||
$this->renderItemLink($item, $params['randlinks']);
|
||||
$renderer->tablecell_close();
|
||||
|
||||
if ($params['showsize']) {
|
||||
$renderer->tablecell_open(1, 'right');
|
||||
if (!empty($item['isdir'])) {
|
||||
$renderer->cdata('');
|
||||
} else {
|
||||
$renderer->cdata(filesize_h($item['size']));
|
||||
}
|
||||
$renderer->tablecell_close();
|
||||
}
|
||||
|
||||
if ($params['showdate']) {
|
||||
$renderer->tablecell_open();
|
||||
$renderer->cdata(dformat($item['mtime']));
|
||||
$renderer->tablecell_close();
|
||||
}
|
||||
|
||||
$renderer->tablerow_close();
|
||||
}
|
||||
}
|
||||
$renderer->tabletbody_close();
|
||||
$renderer->table_close();
|
||||
|
||||
62
style.css
62
style.css
@@ -392,3 +392,65 @@ html.luxtools-noscroll body {
|
||||
font-size: 2.4em;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* Imagebox (Wikipedia-style image with caption)
|
||||
* ======================================================================== */
|
||||
|
||||
.luxtools-imagebox {
|
||||
margin-bottom: 0.5em;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.luxtools-imagebox.tleft {
|
||||
clear: left;
|
||||
float: left;
|
||||
margin-right: 1.4em;
|
||||
}
|
||||
|
||||
.luxtools-imagebox.tright {
|
||||
clear: right;
|
||||
float: right;
|
||||
margin-left: 1.4em;
|
||||
}
|
||||
|
||||
.luxtools-imagebox.tcenter {
|
||||
clear: both;
|
||||
text-align: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.luxtools-imagebox.tcenter .luxtools-imagebox-inner {
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.luxtools-imagebox .luxtools-imagebox-inner {
|
||||
display: inline-block;
|
||||
background-color: @ini_background_alt;
|
||||
border: 1px solid @ini_border;
|
||||
padding: 3px;
|
||||
font-size: 94%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.luxtools-imagebox .luxtools-imagebox-inner > a {
|
||||
display: block;
|
||||
line-height: 0;
|
||||
background-color: @ini_background;
|
||||
}
|
||||
|
||||
.luxtools-imagebox .luxtools-imagebox-inner img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.luxtools-imagebox .luxtools-imagebox-caption {
|
||||
border: none;
|
||||
font-size: 94%;
|
||||
line-height: 1.4em;
|
||||
padding: 3px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@@ -82,13 +82,6 @@ abstract class syntax_plugin_luxtools_abstract extends SyntaxPlugin
|
||||
/** @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, '');
|
||||
@@ -161,6 +154,12 @@ abstract class syntax_plugin_luxtools_abstract extends SyntaxPlugin
|
||||
*/
|
||||
protected function parseFlags(string $flags): array
|
||||
{
|
||||
// Parse default table columns setting.
|
||||
// Format: comma-separated list of column names (name, size, date).
|
||||
$tableColumns = strtolower(trim((string)$this->getConf('default_tablecolumns')));
|
||||
$defaultShowSize = str_contains($tableColumns, 'size') ? 1 : (int)$this->getConf('default_showsize');
|
||||
$defaultShowDate = str_contains($tableColumns, 'date') ? 1 : (int)$this->getConf('default_showdate');
|
||||
|
||||
// Base defaults shared by all handlers
|
||||
$baseDefaults = [
|
||||
'sort' => (string)$this->getConf('default_sort'),
|
||||
@@ -172,8 +171,8 @@ abstract class syntax_plugin_luxtools_abstract extends SyntaxPlugin
|
||||
'titlefile' => (string)$this->getConf('default_titlefile'),
|
||||
'cache' => (int)$this->getConf('default_cache'),
|
||||
'randlinks' => (int)$this->getConf('default_randlinks'),
|
||||
'showsize' => (int)$this->getConf('default_showsize'),
|
||||
'showdate' => (int)$this->getConf('default_showdate'),
|
||||
'showsize' => $defaultShowSize,
|
||||
'showdate' => $defaultShowDate,
|
||||
'listsep' => (string)$this->getConf('default_listsep'),
|
||||
'maxheight' => (int)$this->getConf('default_maxheight'),
|
||||
];
|
||||
|
||||
@@ -54,14 +54,10 @@ class syntax_plugin_luxtools_directory extends syntax_plugin_luxtools_abstract
|
||||
$params['titlefile']
|
||||
);
|
||||
|
||||
if ($items == []) {
|
||||
$this->renderEmptyState($renderer, 'empty_files');
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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->renderAsFlatTable($params);
|
||||
return true;
|
||||
|
||||
@@ -41,9 +41,9 @@ class syntax_plugin_luxtools_files extends syntax_plugin_luxtools_abstract
|
||||
$params['titlefile']
|
||||
);
|
||||
|
||||
if ($result == []) {
|
||||
$this->renderEmptyState($renderer, 'empty_files');
|
||||
return true;
|
||||
// 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);
|
||||
|
||||
242
syntax/image.php
Normal file
242
syntax/image.php
Normal file
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
|
||||
use dokuwiki\Extension\SyntaxPlugin;
|
||||
use dokuwiki\plugin\luxtools\Path;
|
||||
|
||||
require_once(__DIR__ . '/../autoload.php');
|
||||
|
||||
/**
|
||||
* luxtools Plugin: Image syntax.
|
||||
*
|
||||
* Renders a single image in an imagebox (similar to Wikipedia-style image boxes).
|
||||
* Syntax: {{image>/path/to/image.jpg|Caption text}}
|
||||
*
|
||||
*/
|
||||
class syntax_plugin_luxtools_image extends SyntaxPlugin
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function getType()
|
||||
{
|
||||
return 'substition';
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function getPType()
|
||||
{
|
||||
return 'block';
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function getSort()
|
||||
{
|
||||
return 315; // Same as imagebox plugin
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function connectTo($mode)
|
||||
{
|
||||
$this->Lexer->addSpecialPattern('\{\{image>.+?\}\}', $mode, 'plugin_luxtools_image');
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function handle($match, $state, $pos, \Doku_Handler $handler)
|
||||
{
|
||||
// Remove the leading {{image> and trailing }}
|
||||
$match = substr($match, strlen('{{image>'), -2);
|
||||
|
||||
// Split path and caption by |
|
||||
$parts = explode('|', $match, 2);
|
||||
$pathPart = trim($parts[0]);
|
||||
$caption = isset($parts[1]) ? trim($parts[1]) : '';
|
||||
|
||||
// Parse optional parameters from path (e.g., /path/image.jpg?200x150&right)
|
||||
// Supported formats:
|
||||
// ?200 - width only
|
||||
// ?200x150 - width and height
|
||||
// ?left - alignment only (left, right, center)
|
||||
// ?200&right - width and alignment
|
||||
// ?200x150¢er - full options
|
||||
$width = null;
|
||||
$height = null;
|
||||
$align = 'right'; // default alignment
|
||||
|
||||
if (strpos($pathPart, '?') !== false) {
|
||||
[$pathPart, $paramStr] = explode('?', $pathPart, 2);
|
||||
$paramParts = explode('&', $paramStr);
|
||||
|
||||
foreach ($paramParts as $param) {
|
||||
$param = trim($param);
|
||||
if ($param === '') continue;
|
||||
|
||||
// Check if it's an alignment keyword
|
||||
if (in_array($param, ['left', 'right', 'center'], true)) {
|
||||
$align = $param;
|
||||
// Check if it's a size specification (digits, optionally with 'x' and more digits)
|
||||
} elseif (preg_match('/^(\d+)(?:x(\d+))?$/', $param, $m)) {
|
||||
$width = (int)$m[1];
|
||||
if (isset($m[2]) && $m[2] !== '') {
|
||||
$height = (int)$m[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$path = Path::cleanPath($pathPart, false);
|
||||
|
||||
return [
|
||||
'path' => $path,
|
||||
'caption' => $caption,
|
||||
'align' => $align,
|
||||
'width' => $width,
|
||||
'height' => $height,
|
||||
];
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function render($format, \Doku_Renderer $renderer, $data)
|
||||
{
|
||||
if ($data === false || !is_array($data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($format !== 'xhtml') {
|
||||
// For non-XHTML formats, render caption as text if available.
|
||||
if (!empty($data['caption'])) {
|
||||
$renderer->cdata('[Image: ' . $data['caption'] . ']');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
$pathHelper = new Path($this->getConf('paths'));
|
||||
// Use addTrailingSlash=false since this is a file path, not a directory
|
||||
$pathInfo = $pathHelper->getPathInfo($data['path'], false);
|
||||
} catch (\Exception $e) {
|
||||
$renderer->cdata('[n/a: ' . $this->getLang('error_outsidejail') . ']');
|
||||
return true;
|
||||
}
|
||||
|
||||
$fullPath = $pathInfo['root'] . $pathInfo['local'];
|
||||
|
||||
// Verify the file exists and is an image
|
||||
if (!is_file($fullPath)) {
|
||||
$renderer->cdata('[n/a: File not found]');
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if it's an image
|
||||
try {
|
||||
[, $mime,] = mimetype($fullPath, false);
|
||||
} catch (\Throwable $e) {
|
||||
$mime = null;
|
||||
}
|
||||
if (!is_string($mime) || !str_starts_with($mime, 'image/')) {
|
||||
$renderer->cdata('[n/a: Not an image]');
|
||||
return true;
|
||||
}
|
||||
|
||||
// Build the image URL using the plugin's file.php endpoint
|
||||
global $ID;
|
||||
$imageUrl = $this->buildFileUrl($pathInfo, $data['width'], $data['height']);
|
||||
|
||||
// Build full-size URL for linking
|
||||
$fullUrl = $this->buildFileUrl($pathInfo, null, null);
|
||||
|
||||
$this->renderImageBox($renderer, $imageUrl, $fullUrl, $data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the file.php URL for the image.
|
||||
*
|
||||
* @param array $pathInfo Path info from Path helper
|
||||
* @param int|null $width Optional width
|
||||
* @param int|null $height Optional height
|
||||
* @return string
|
||||
*/
|
||||
protected function buildFileUrl(array $pathInfo, ?int $width, ?int $height): string
|
||||
{
|
||||
global $ID;
|
||||
|
||||
$params = [
|
||||
'root' => $pathInfo['root'],
|
||||
'file' => $pathInfo['local'],
|
||||
'id' => $ID,
|
||||
];
|
||||
|
||||
if ($width !== null) {
|
||||
$params['w'] = $width;
|
||||
}
|
||||
if ($height !== null) {
|
||||
$params['h'] = $height;
|
||||
}
|
||||
|
||||
return DOKU_BASE . 'lib/plugins/luxtools/file.php?' . http_build_query($params, '', '&');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the imagebox HTML.
|
||||
*
|
||||
* @param \Doku_Renderer $renderer
|
||||
* @param string $imageUrl URL for the displayed image
|
||||
* @param string $fullUrl URL for the full-size image (on click)
|
||||
* @param array $data Parsed data from handle()
|
||||
*/
|
||||
protected function renderImageBox(\Doku_Renderer $renderer, string $imageUrl, string $fullUrl, array $data): void
|
||||
{
|
||||
$align = $data['align'] ?? 'right';
|
||||
$caption = $data['caption'] ?? '';
|
||||
$width = $data['width'];
|
||||
$height = $data['height'];
|
||||
|
||||
// Alignment class
|
||||
$alignClass = 'tright'; // default
|
||||
if ($align === 'left') {
|
||||
$alignClass = 'tleft';
|
||||
} elseif ($align === 'center') {
|
||||
$alignClass = 'tcenter';
|
||||
}
|
||||
|
||||
// Build width style for the outer container
|
||||
$outerStyle = '';
|
||||
if ($width !== null) {
|
||||
// Add a few pixels for border/padding
|
||||
$outerStyle = ' style="width: ' . ($width + 10) . 'px;"';
|
||||
}
|
||||
|
||||
// Build image attributes
|
||||
$imgAttrs = 'class="media" loading="lazy" decoding="async"';
|
||||
if ($width !== null) {
|
||||
$imgAttrs .= ' width="' . (int)$width . '"';
|
||||
}
|
||||
if ($height !== null) {
|
||||
$imgAttrs .= ' height="' . (int)$height . '"';
|
||||
}
|
||||
$imgAttrs .= ' alt="' . hsc($caption) . '"';
|
||||
|
||||
/** @var \Doku_Renderer_xhtml $renderer */
|
||||
$renderer->doc .= '<div class="luxtools-imagebox ' . $alignClass . '"' . $outerStyle . '>';
|
||||
$renderer->doc .= '<div class="luxtools-imagebox-inner">';
|
||||
|
||||
// Image with link to full size
|
||||
$renderer->doc .= '<a href="' . hsc($fullUrl) . '" class="media" target="_blank">';
|
||||
$renderer->doc .= '<img src="' . hsc($imageUrl) . '" ' . $imgAttrs . ' />';
|
||||
$renderer->doc .= '</a>';
|
||||
|
||||
// Caption
|
||||
if ($caption !== '') {
|
||||
// Calculate max caption width
|
||||
$captionStyle = '';
|
||||
if ($width !== null) {
|
||||
$captionStyle = ' style="max-width: ' . ($width - 6) . 'px;"';
|
||||
}
|
||||
$renderer->doc .= '<div class="luxtools-imagebox-caption"' . $captionStyle . '>';
|
||||
$renderer->doc .= hsc($caption);
|
||||
$renderer->doc .= '</div>';
|
||||
}
|
||||
|
||||
$renderer->doc .= '</div>';
|
||||
$renderer->doc .= '</div>';
|
||||
}
|
||||
}
|
||||
@@ -42,13 +42,6 @@ class syntax_plugin_luxtools_scratchpad extends SyntaxPlugin
|
||||
/** @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;
|
||||
}
|
||||
|
||||
$match = substr($match, strlen('{{scratchpad>'), -2);
|
||||
[$path,] = array_pad(explode('&', $match, 2), 2, '');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user