Inial implementation for folder opening
This commit is contained in:
@@ -213,4 +213,24 @@ class plugin_filetools_test extends DokuWikiTest
|
|||||||
|
|
||||||
$this->assertStringContainsString('exampleimage.png', $xhtml);
|
$this->assertStringContainsString('exampleimage.png', $xhtml);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function checks that the open syntax renders an inline button.
|
||||||
|
*/
|
||||||
|
public function test_open_button()
|
||||||
|
{
|
||||||
|
$instructions = p_get_instructions('{{open>/tmp/somewhere|Open here}}');
|
||||||
|
$xhtml = p_render('xhtml', $instructions, $info);
|
||||||
|
|
||||||
|
$doc = new Document();
|
||||||
|
$doc->html($xhtml);
|
||||||
|
|
||||||
|
$structure = [
|
||||||
|
'button.filetools-open' => 1,
|
||||||
|
];
|
||||||
|
$this->structureCheck($doc, $structure);
|
||||||
|
|
||||||
|
$this->assertStringContainsString('Open here', $xhtml);
|
||||||
|
$this->assertStringContainsString('data-path="/tmp/somewhere"', $xhtml);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
58
script.js
Normal file
58
script.js
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/* global window, document */
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function normalizeToFileUrl(path) {
|
||||||
|
if (!path) return '';
|
||||||
|
|
||||||
|
// already a file URL
|
||||||
|
if (/^file:\/\//i.test(path)) return path;
|
||||||
|
|
||||||
|
// UNC path: \\server\share\path
|
||||||
|
if (/^\\\\/.test(path)) {
|
||||||
|
var p = path.replace(/^\\\\/, '');
|
||||||
|
p = p.replace(/\\/g, '/');
|
||||||
|
return 'file://///' + p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Windows drive: C:\path\to\file
|
||||||
|
if (/^[a-zA-Z]:\\/.test(path)) {
|
||||||
|
var drive = path[0].toUpperCase();
|
||||||
|
var rest = path.slice(2).replace(/\\/g, '/');
|
||||||
|
return 'file:///' + drive + ':' + rest;
|
||||||
|
}
|
||||||
|
|
||||||
|
// POSIX absolute: /home/user/file
|
||||||
|
if (path[0] === '/') {
|
||||||
|
return 'file://' + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to using the provided string.
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onClick(event) {
|
||||||
|
var el = event.target;
|
||||||
|
if (!el || !el.classList || !el.classList.contains('filetools-open')) return;
|
||||||
|
|
||||||
|
var raw = el.getAttribute('data-path') || '';
|
||||||
|
var url = normalizeToFileUrl(raw);
|
||||||
|
console.log('Opening file URL:', url);
|
||||||
|
if (!url) return;
|
||||||
|
|
||||||
|
// Best-effort: browsers may block file:// navigation depending on settings.
|
||||||
|
try {
|
||||||
|
window.open(url, '_blank', 'noopener');
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to open file URL in new tab:', e);
|
||||||
|
try {
|
||||||
|
window.location.href = url;
|
||||||
|
} catch (e2) {
|
||||||
|
console.error('Failed to open file URL:', e2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('click', onClick, false);
|
||||||
|
})();
|
||||||
79
syntax/open.php
Normal file
79
syntax/open.php
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use dokuwiki\Extension\SyntaxPlugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File Tools Plugin: Open local path syntax.
|
||||||
|
*
|
||||||
|
* Renders an inline button. Clicking it triggers client-side JS that attempts
|
||||||
|
* to open the configured path in the default file manager (best-effort).
|
||||||
|
*/
|
||||||
|
class syntax_plugin_filetools_open extends SyntaxPlugin
|
||||||
|
{
|
||||||
|
/** @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_filetools_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
$renderer->doc .= '<button type="button" class="filetools-open" data-path="' . hsc($path) . '">' . hsc($caption) . '</button>';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user