Extract Pagelink functionality

This commit is contained in:
2026-02-03 08:00:09 +01:00
parent 1b6df4a9e4
commit 70a9f30336
4 changed files with 172 additions and 278 deletions

162
src/PageLinkTrait.php Normal file
View File

@@ -0,0 +1,162 @@
<?php
namespace dokuwiki\plugin\luxtools;
/**
* Trait for pagelink-related functionality shared across syntax handlers.
*
* Provides methods for:
* - Detecting blobs alias paths
* - Resolving the blobs root folder from page metadata
* - Rendering "page not linked" messages
* - Building path configs with blobs alias support
*
* Requirements for using classes:
* - Must have getConf() method (from SyntaxPlugin)
* - Must have getLang() method (from SyntaxPlugin)
*/
trait PageLinkTrait
{
/**
* Check if the given path uses the blobs alias.
*
* @param string $path
* @return bool
*/
protected function isBlobsPath(string $path): bool
{
$trimmed = ltrim($path, '/');
return preg_match('/^blobs(\/|$)/', $trimmed) === 1;
}
/**
* Render the "Page not linked" message with copy ID affordance.
*
* @param \Doku_Renderer $renderer
*/
protected function renderPageNotLinked(\Doku_Renderer $renderer): void
{
$uuid = $this->getPageUuidSafe();
$text = (string)$this->getLang('pagelink_unlinked');
if ($renderer instanceof \Doku_Renderer_xhtml) {
$renderer->doc .= '<a href="#" class="luxtools-pagelink-copy" data-luxtools-pagelink-copy="1"'
. ' data-uuid="' . hsc($uuid) . '"'
. '>' . hsc($text) . '</a>';
return;
}
$renderer->cdata('[n/a: ' . $text . ']');
}
/**
* Read the current page UUID (if any).
*
* @return string The UUID or empty string
*/
protected function getPageUuidSafe(): string
{
global $ID;
$pageId = is_string($ID) ? $ID : '';
if ($pageId === '') return '';
if (function_exists('cleanID')) {
$pageId = (string)cleanID($pageId);
}
if ($pageId === '') return '';
$depth = (int)$this->getConf('pagelink_search_depth');
if ($depth < 0) $depth = 0;
$pageLink = new PageLink((string)$this->getConf('paths'), $depth);
$uuid = $pageLink->getPageUuid($pageId);
return $uuid ?? '';
}
/**
* Resolve the current page's pagelink folder for the blobs alias.
*
* Results are cached per page ID within a single request.
*
* @return string The linked folder path or empty string if not linked
*/
protected function resolveBlobsRoot(): string
{
static $cached = [];
global $ID;
$pageId = is_string($ID) ? $ID : '';
if ($pageId === '') return '';
if (function_exists('cleanID')) {
$pageId = (string)cleanID($pageId);
}
if ($pageId === '') return '';
if (isset($cached[$pageId])) {
return (string)$cached[$pageId];
}
$depth = (int)$this->getConf('pagelink_search_depth');
if ($depth < 0) $depth = 0;
$pageLink = new PageLink((string)$this->getConf('paths'), $depth);
$uuid = $pageLink->getPageUuid($pageId);
if ($uuid === null) {
$cached[$pageId] = '';
return '';
}
$linkInfo = $pageLink->resolveUuid($uuid);
$folder = $linkInfo['folder'] ?? '';
if (!is_string($folder) || $folder === '') {
$cached[$pageId] = '';
return '';
}
$cached[$pageId] = $folder;
return $folder;
}
/**
* Build a path config string with the blobs alias appended (if available).
*
* @param string|null $blobsRoot The blobs root folder (or null to auto-resolve)
* @return string The path config string
*/
protected function buildPathConfigWithBlobs(?string $blobsRoot = null): string
{
$pathConfig = (string)$this->getConf('paths');
if ($blobsRoot === null) {
$blobsRoot = $this->resolveBlobsRoot();
}
if ($blobsRoot !== '') {
$pathConfig = rtrim($pathConfig) . "\n" . $blobsRoot . "\nA> blobs";
}
return $pathConfig;
}
/**
* Create a Path helper with blobs alias support.
*
* @param string|null $blobsRoot The blobs root folder (or null to auto-resolve)
* @return Path
*/
protected function createPathHelperWithBlobs(?string $blobsRoot = null): Path
{
return new Path($this->buildPathConfigWithBlobs($blobsRoot));
}
/**
* Create a Path helper using only the base paths config (no blobs alias).
*
* @return Path
*/
protected function createPathHelper(): Path
{
return new Path((string)$this->getConf('paths'));
}
}

View File

@@ -4,7 +4,7 @@ use dokuwiki\Extension\SyntaxPlugin;
use dokuwiki\plugin\luxtools\Crawler; use dokuwiki\plugin\luxtools\Crawler;
use dokuwiki\plugin\luxtools\Output; use dokuwiki\plugin\luxtools\Output;
use dokuwiki\plugin\luxtools\Path; use dokuwiki\plugin\luxtools\Path;
use dokuwiki\plugin\luxtools\PageLink; use dokuwiki\plugin\luxtools\PageLinkTrait;
require_once(__DIR__ . '/../autoload.php'); require_once(__DIR__ . '/../autoload.php');
@@ -16,6 +16,7 @@ require_once(__DIR__ . '/../autoload.php');
if (!class_exists('syntax_plugin_luxtools_abstract', false)) { if (!class_exists('syntax_plugin_luxtools_abstract', false)) {
abstract class syntax_plugin_luxtools_abstract extends SyntaxPlugin abstract class syntax_plugin_luxtools_abstract extends SyntaxPlugin
{ {
use PageLinkTrait;
/** /**
* Returns the syntax keyword (e.g., 'files', 'directory', 'images'). * Returns the syntax keyword (e.g., 'files', 'directory', 'images').
* Used for pattern matching and plugin registration. * Used for pattern matching and plugin registration.
@@ -209,16 +210,12 @@ abstract class syntax_plugin_luxtools_abstract extends SyntaxPlugin
protected function getPathInfoSafe(string $basePath, \Doku_Renderer $renderer) protected function getPathInfoSafe(string $basePath, \Doku_Renderer $renderer)
{ {
try { try {
$pathConfig = (string)$this->getConf('paths');
$blobsRoot = $this->resolveBlobsRoot(); $blobsRoot = $this->resolveBlobsRoot();
if ($blobsRoot === '' && $this->isBlobsPath($basePath)) { if ($blobsRoot === '' && $this->isBlobsPath($basePath)) {
$this->renderPageNotLinked($renderer); $this->renderPageNotLinked($renderer);
return false; return false;
} }
if ($blobsRoot !== '') { $pathHelper = $this->createPathHelperWithBlobs($blobsRoot);
$pathConfig = rtrim($pathConfig) . "\n" . $blobsRoot . "\nA> blobs";
}
$pathHelper = new Path($pathConfig);
return $pathHelper->getPathInfo($basePath); return $pathHelper->getPathInfo($basePath);
} catch (\Exception $e) { } catch (\Exception $e) {
$this->renderError($renderer, 'error_outsidejail'); $this->renderError($renderer, 'error_outsidejail');
@@ -226,99 +223,6 @@ abstract class syntax_plugin_luxtools_abstract extends SyntaxPlugin
} }
} }
/**
* Check if the given path uses the blobs alias.
*/
protected function isBlobsPath(string $path): bool
{
$trimmed = ltrim($path, '/');
return preg_match('/^blobs(\/|$)/', $trimmed) === 1;
}
/**
* Render the "Page not linked" message with copy ID affordance.
*/
protected function renderPageNotLinked(\Doku_Renderer $renderer): void
{
$uuid = $this->getPageUuidSafe();
$text = (string)$this->getLang('pagelink_unlinked');
if ($renderer instanceof \Doku_Renderer_xhtml) {
$renderer->doc .= '<a href="#" class="luxtools-pagelink-copy" data-luxtools-pagelink-copy="1"'
. ' data-uuid="' . hsc($uuid) . '"'
. '>' . hsc($text) . '</a>';
return;
}
$renderer->cdata('[n/a: ' . $text . ']');
}
/**
* Read the current page UUID (if any).
*/
protected function getPageUuidSafe(): string
{
global $ID;
$pageId = is_string($ID) ? $ID : '';
if ($pageId === '') return '';
if (function_exists('cleanID')) {
$pageId = (string)cleanID($pageId);
}
if ($pageId === '') return '';
$depth = (int)$this->getConf('pagelink_search_depth');
if ($depth < 0) $depth = 0;
$pageLink = new PageLink((string)$this->getConf('paths'), $depth);
$uuid = $pageLink->getPageUuid($pageId);
return $uuid ?? '';
}
/**
* Resolve the current page's pagelink folder for the blobs alias.
*
* @return string
*/
protected function resolveBlobsRoot(): string
{
static $cached = [];
global $ID;
$pageId = is_string($ID) ? $ID : '';
if ($pageId === '') return '';
if (function_exists('cleanID')) {
$pageId = (string)cleanID($pageId);
}
if ($pageId === '') return '';
if (isset($cached[$pageId])) {
return (string)$cached[$pageId];
}
$pathConfig = (string)$this->getConf('paths');
$depth = (int)$this->getConf('pagelink_search_depth');
if ($depth < 0) $depth = 0;
$pageLink = new PageLink($pathConfig, $depth);
$uuid = $pageLink->getPageUuid($pageId);
if ($uuid === null) {
$cached[$pageId] = '';
return '';
}
$linkInfo = $pageLink->resolveUuid($uuid);
$folder = $linkInfo['folder'] ?? '';
if (!is_string($folder) || $folder === '') {
$cached[$pageId] = '';
return '';
}
$cached[$pageId] = $folder;
return $folder;
}
/** /**
* Create and configure a Crawler instance. * Create and configure a Crawler instance.
* *

View File

@@ -2,7 +2,7 @@
use dokuwiki\Extension\SyntaxPlugin; use dokuwiki\Extension\SyntaxPlugin;
use dokuwiki\plugin\luxtools\Path; use dokuwiki\plugin\luxtools\Path;
use dokuwiki\plugin\luxtools\PageLink; use dokuwiki\plugin\luxtools\PageLinkTrait;
use dokuwiki\plugin\luxtools\ThumbnailHelper; use dokuwiki\plugin\luxtools\ThumbnailHelper;
require_once(__DIR__ . '/../autoload.php'); require_once(__DIR__ . '/../autoload.php');
@@ -16,6 +16,7 @@ require_once(__DIR__ . '/../autoload.php');
*/ */
class syntax_plugin_luxtools_image extends SyntaxPlugin class syntax_plugin_luxtools_image extends SyntaxPlugin
{ {
use PageLinkTrait;
/** @inheritdoc */ /** @inheritdoc */
public function getType() public function getType()
{ {
@@ -139,12 +140,7 @@ class syntax_plugin_luxtools_image extends SyntaxPlugin
return true; return true;
} }
$pathConfig = (string)$this->getConf('paths'); $pathHelper = $this->createPathHelperWithBlobs($blobsRoot);
if ($blobsRoot !== '') {
$pathConfig = rtrim($pathConfig) . "\n" . $blobsRoot . "\nA> blobs";
}
$pathHelper = new Path($pathConfig);
// Use addTrailingSlash=false since this is a file path, not a directory // Use addTrailingSlash=false since this is a file path, not a directory
$pathInfo = $pathHelper->getPathInfo($data['path'], false); $pathInfo = $pathHelper->getPathInfo($data['path'], false);
} catch (\Exception $e) { } catch (\Exception $e) {
@@ -226,96 +222,6 @@ class syntax_plugin_luxtools_image extends SyntaxPlugin
return DOKU_BASE . 'lib/plugins/luxtools/file.php?' . http_build_query($params, '', '&'); return DOKU_BASE . 'lib/plugins/luxtools/file.php?' . http_build_query($params, '', '&');
} }
/**
* Check if the given path uses the blobs alias.
*/
protected function isBlobsPath(string $path): bool
{
$trimmed = ltrim($path, '/');
return preg_match('/^blobs(\/|$)/', $trimmed) === 1;
}
/**
* Render the "Page not linked" message with copy ID affordance.
*/
protected function renderPageNotLinked(\Doku_Renderer $renderer): void
{
$uuid = $this->getPageUuidSafe();
$text = (string)$this->getLang('pagelink_unlinked');
if ($renderer instanceof \Doku_Renderer_xhtml) {
$renderer->doc .= '<a href="#" class="luxtools-pagelink-copy" data-luxtools-pagelink-copy="1"'
. ' data-uuid="' . hsc($uuid) . '"'
. '>' . hsc($text) . '</a>';
return;
}
$renderer->cdata('[n/a: ' . $text . ']');
}
/**
* Read the current page UUID (if any).
*/
protected function getPageUuidSafe(): string
{
global $ID;
$pageId = is_string($ID) ? $ID : '';
if ($pageId === '') return '';
if (function_exists('cleanID')) {
$pageId = (string)cleanID($pageId);
}
if ($pageId === '') return '';
$depth = (int)$this->getConf('pagelink_search_depth');
if ($depth < 0) $depth = 0;
$pageLink = new PageLink((string)$this->getConf('paths'), $depth);
$uuid = $pageLink->getPageUuid($pageId);
return $uuid ?? '';
}
/**
* Resolve the current page's pagelink folder for the blobs alias.
*/
protected function resolveBlobsRoot(): string
{
static $cached = [];
global $ID;
$pageId = is_string($ID) ? $ID : '';
if ($pageId === '') return '';
if (function_exists('cleanID')) {
$pageId = (string)cleanID($pageId);
}
if ($pageId === '') return '';
if (isset($cached[$pageId])) {
return (string)$cached[$pageId];
}
$depth = (int)$this->getConf('pagelink_search_depth');
if ($depth < 0) $depth = 0;
$pageLink = new PageLink((string)$this->getConf('paths'), $depth);
$uuid = $pageLink->getPageUuid($pageId);
if ($uuid === null) {
$cached[$pageId] = '';
return '';
}
$linkInfo = $pageLink->resolveUuid($uuid);
$folder = $linkInfo['folder'] ?? '';
if (!is_string($folder) || $folder === '') {
$cached[$pageId] = '';
return '';
}
$cached[$pageId] = $folder;
return $folder;
}
/** /**
* Render the imagebox HTML. * Render the imagebox HTML.
* *

View File

@@ -1,7 +1,7 @@
<?php <?php
use dokuwiki\Extension\SyntaxPlugin; use dokuwiki\Extension\SyntaxPlugin;
use dokuwiki\plugin\luxtools\PageLink; use dokuwiki\plugin\luxtools\PageLinkTrait;
use dokuwiki\plugin\luxtools\Path; use dokuwiki\plugin\luxtools\Path;
require_once(__DIR__ . '/../autoload.php'); require_once(__DIR__ . '/../autoload.php');
@@ -14,6 +14,7 @@ require_once(__DIR__ . '/../autoload.php');
*/ */
class syntax_plugin_luxtools_open extends SyntaxPlugin class syntax_plugin_luxtools_open extends SyntaxPlugin
{ {
use PageLinkTrait;
/** @inheritdoc */ /** @inheritdoc */
public function getType() public function getType()
{ {
@@ -86,9 +87,7 @@ class syntax_plugin_luxtools_open extends SyntaxPlugin
} }
try { try {
$pathConfig = (string)$this->getConf('paths'); $pathHelper = $this->createPathHelperWithBlobs($blobsRoot);
$pathConfig = rtrim($pathConfig) . "\n" . $blobsRoot . "\nA> blobs";
$pathHelper = new Path($pathConfig);
$resolvedPath = $path; $resolvedPath = $path;
$isBlobsRoot = (rtrim($resolvedPath, '/') === 'blobs'); $isBlobsRoot = (rtrim($resolvedPath, '/') === 'blobs');
if ($isBlobsRoot) { if ($isBlobsRoot) {
@@ -105,7 +104,7 @@ class syntax_plugin_luxtools_open extends SyntaxPlugin
// Map local paths back to their configured aliases before opening. // Map local paths back to their configured aliases before opening.
if (!preg_match('/^[a-zA-Z][a-zA-Z0-9+.-]*:/', $path)) { if (!preg_match('/^[a-zA-Z][a-zA-Z0-9+.-]*:/', $path)) {
try { try {
$pathHelper = new Path((string)$this->getConf('paths')); $pathHelper = $this->createPathHelper();
$path = $pathHelper->mapToAliasPath($path); $path = $pathHelper->mapToAliasPath($path);
} catch (\Exception $e) { } catch (\Exception $e) {
// ignore mapping failures // ignore mapping failures
@@ -145,81 +144,4 @@ class syntax_plugin_luxtools_open extends SyntaxPlugin
$renderer->doc .= $renderer->_formatLink($link); $renderer->doc .= $renderer->_formatLink($link);
return true; return true;
} }
/**
* Check if the given path uses the blobs alias.
*/
protected function isBlobsPath(string $path): bool
{
$trimmed = ltrim($path, '/');
return preg_match('/^blobs(\/|$)/', $trimmed) === 1;
}
/**
* Resolve the current page's pagelink folder for the blobs alias.
*/
protected function resolveBlobsRoot(): string
{
global $ID;
$pageId = is_string($ID) ? $ID : '';
if ($pageId === '') return '';
if (function_exists('cleanID')) {
$pageId = (string)cleanID($pageId);
}
if ($pageId === '') return '';
$depth = (int)$this->getConf('pagelink_search_depth');
if ($depth < 0) $depth = 0;
$pageLink = new PageLink((string)$this->getConf('paths'), $depth);
$uuid = $pageLink->getPageUuid($pageId);
if ($uuid === null) return '';
$linkInfo = $pageLink->resolveUuid($uuid);
$folder = $linkInfo['folder'] ?? '';
if (!is_string($folder) || $folder === '') return '';
return $folder;
}
/**
* Render the "Page not linked" message with copy ID affordance.
*/
protected function renderPageNotLinked(\Doku_Renderer $renderer): void
{
$uuid = $this->getPageUuidSafe();
$text = (string)$this->getLang('pagelink_unlinked');
if ($renderer instanceof \Doku_Renderer_xhtml) {
$renderer->doc .= '<a href="#" class="luxtools-pagelink-copy" data-luxtools-pagelink-copy="1"'
. ' data-uuid="' . hsc($uuid) . '"'
. '>' . hsc($text) . '</a>';
return;
}
$renderer->cdata('[n/a: ' . $text . ']');
}
/**
* Read the current page UUID (if any).
*/
protected function getPageUuidSafe(): string
{
global $ID;
$pageId = is_string($ID) ? $ID : '';
if ($pageId === '') return '';
if (function_exists('cleanID')) {
$pageId = (string)cleanID($pageId);
}
if ($pageId === '') return '';
$depth = (int)$this->getConf('pagelink_search_depth');
if ($depth < 0) $depth = 0;
$pageLink = new PageLink((string)$this->getConf('paths'), $depth);
$uuid = $pageLink->getPageUuid($pageId);
return $uuid ?? '';
}
} }