Files
luxtools-plugin/syntax/open.php

162 lines
5.3 KiB
PHP

<?php
use dokuwiki\Extension\SyntaxPlugin;
use dokuwiki\plugin\luxtools\PageLinkTrait;
use dokuwiki\plugin\luxtools\Path;
require_once(__DIR__ . '/../autoload.php');
/**
* luxtools Plugin: Open local path syntax.
*
* Renders an inline link. Clicking it triggers client-side JS that attempts
* to open the configured path in the default file manager (best-effort).
*/
class syntax_plugin_luxtools_open extends SyntaxPlugin
{
use PageLinkTrait;
/** @inheritdoc */
public function getType()
{
return 'substition';
}
/** @inheritdoc */
public function getPType()
{
// inline
return 'normal';
}
/** @inheritdoc */
public function getSort()
{
return 222;
}
/** @inheritdoc */
public function connectTo($mode)
{
$this->Lexer->addSpecialPattern('\{\{open>.+?\}\}', $mode, 'plugin_luxtools_open');
}
/** @inheritdoc */
public function handle($match, $state, $pos, Doku_Handler $handler)
{
$match = substr($match, strlen('{{open>'), -2);
[$path, $caption] = array_pad(explode('|', $match, 2), 2, '');
$path = trim($path);
$caption = trim($caption);
if ($caption === '') $caption = $path !== '' ? $path : 'Open';
// Basic scheme filtering to avoid javascript: style injections.
// Allow either file:// URLs, or plain paths (Windows/UNC/Linux style).
if (preg_match('/^[a-zA-Z][a-zA-Z0-9+.-]*:/', $path)) {
if (!str_starts_with(strtolower($path), 'file://')) {
return false;
}
}
return [$path, $caption];
}
/** @inheritdoc */
public function render($format, Doku_Renderer $renderer, $data)
{
if ($data === false) return false;
[$path, $caption] = $data;
if ($format !== 'xhtml') {
// no meaningful representation in non-browser formats
$renderer->cdata($caption);
return true;
}
if ($path === '') {
$renderer->cdata('[n/a]');
return true;
}
// Resolve blobs alias to the linked folder (if available)
if ($this->isBlobsPath($path)) {
$blobsRoot = $this->resolveBlobsRoot();
if ($blobsRoot === '') {
$this->renderPageNotLinked($renderer);
return true;
}
try {
$pathHelper = $this->createPathHelperWithBlobs($blobsRoot);
$resolvedPath = $path;
$isBlobsRoot = (rtrim($resolvedPath, '/') === 'blobs');
if ($isBlobsRoot) {
$resolvedPath = rtrim($resolvedPath, '/') . '/';
}
$pathInfo = $pathHelper->getPathInfo($resolvedPath, $isBlobsRoot);
$path = $pathInfo['path'];
} catch (\Exception $e) {
$renderer->cdata('[n/a: ' . $this->getLang('error_outsidejail') . ']');
return true;
}
}
// Map local paths back to their configured aliases before opening.
if (!preg_match('/^[a-zA-Z][a-zA-Z0-9+.-]*:/', $path)) {
try {
$pathHelper = $this->createPathHelper();
// If the input itself uses a configured path alias (legacy syntax
// like "alias/sub/path"), resolve it first so the emitted open
// path uses the new client-side alias format "ALIAS>relative".
$resolvedPath = $path;
try {
$pathInfo = $pathHelper->getPathInfo($path, false);
if (isset($pathInfo['path']) && is_string($pathInfo['path']) && $pathInfo['path'] !== '') {
$resolvedPath = $pathInfo['path'];
}
} catch (\Exception $e) {
// keep original path as-is when it is not in configured roots
}
$path = $pathHelper->mapToAliasPath($resolvedPath);
} catch (\Exception $e) {
// ignore mapping failures
}
}
$serviceUrl = trim((string)$this->getConf('open_service_url'));
$serviceToken = trim((string)$this->getConf('open_service_token'));
if (!($renderer instanceof \Doku_Renderer_xhtml)) {
$renderer->cdata($caption);
return true;
}
global $conf;
/** @var \Doku_Renderer_xhtml $renderer */
// Render like a normal DokuWiki link with an icon in front.
// Use the same folder icon class as directory listings.
$link = [
'target' => $conf['target']['extern'],
'style' => '',
'pre' => '',
'suf' => '',
'name' => $caption,
'url' => '#',
'title' => $renderer->_xmlEntities($path),
'more' => '',
'class' => 'luxtools-open media mediafile mf_folder',
];
$link['more'] .= ' data-path="' . hsc($path) . '"';
if (!empty($conf['relnofollow'])) $link['more'] .= ' rel="nofollow"';
if ($serviceUrl !== '') $link['more'] .= ' data-service-url="' . hsc($serviceUrl) . '"';
if ($serviceToken !== '') $link['more'] .= ' data-service-token="' . hsc($serviceToken) . '"';
$renderer->doc .= $renderer->_formatLink($link);
return true;
}
}