Letzte Version
This commit is contained in:
Binary file not shown.
@@ -5,17 +5,23 @@
|
|||||||
<file driver="mysql" charset="utf8">install/sql/mysql/install.utf8.sql</file>
|
<file driver="mysql" charset="utf8">install/sql/mysql/install.utf8.sql</file>
|
||||||
</sql>
|
</sql>
|
||||||
</install>
|
</install>
|
||||||
<uninstall>
|
<uninstall>
|
||||||
<sql>
|
<sql>
|
||||||
<file driver="mysql" charset="utf8">install/sql/mysql/uninstall.mysql.utf8.sql</file>
|
<file driver="mysql" charset="utf8">install/sql/mysql/uninstall.mysql.utf8.sql</file>
|
||||||
</sql>
|
</sql>
|
||||||
</uninstall>
|
</uninstall>
|
||||||
<name>com_eis</name>
|
<name>com_eis</name>
|
||||||
<creationDate>2025-07-23</creationDate>
|
<creationDate>2025-07-23</creationDate>
|
||||||
<author>Thomas Spohr powert by OpenAI</author>
|
<author>Thomas Spohr powert by OpenAI</author>
|
||||||
<version>1.0.0</version>
|
<version>1.0.0</version>
|
||||||
<description>EIS Minimal-Komponente</description>
|
<description>EIS Minimal-Komponente</description>
|
||||||
<namespace path="src">EIS\Component\EIS</namespace>
|
<namespace path="src">EIS\Component\EIS</namespace>
|
||||||
|
|
||||||
|
<files folder="site">
|
||||||
|
<folder>src</folder>
|
||||||
|
</files>
|
||||||
|
|
||||||
|
|
||||||
<administration>
|
<administration>
|
||||||
<menu>COM_EIS_MENU</menu>
|
<menu>COM_EIS_MENU</menu>
|
||||||
<submenu>
|
<submenu>
|
||||||
|
|||||||
BIN
com_eis/eis.zip
Normal file
BIN
com_eis/eis.zip
Normal file
Binary file not shown.
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace EIS\Component\EIS;
|
namespace EIS\Component\EIS;
|
||||||
|
|
||||||
\defined('_JEXEC') or die;
|
\defined('_JEXEC') or die;
|
||||||
@@ -11,15 +12,24 @@ use Joomla\CMS\Extension\MVCComponent;
|
|||||||
use Joomla\CMS\Dispatcher\ComponentDispatcherFactoryInterface;
|
use Joomla\CMS\Dispatcher\ComponentDispatcherFactoryInterface;
|
||||||
use Joomla\DI\Container;
|
use Joomla\DI\Container;
|
||||||
use Joomla\DI\ServiceProviderInterface;
|
use Joomla\DI\ServiceProviderInterface;
|
||||||
|
use EIS\Component\EIS\Site\Controller\DownloadController;
|
||||||
|
|
||||||
return new class implements ServiceProviderInterface
|
return new class implements ServiceProviderInterface
|
||||||
{
|
{
|
||||||
public function register(Container $container): void
|
public function register(Container $container): void
|
||||||
{
|
{
|
||||||
|
// MVC-Basisregistrierung
|
||||||
$container->registerServiceProvider(new ComponentDispatcherFactory('\\EIS\\Component\\EIS'));
|
$container->registerServiceProvider(new ComponentDispatcherFactory('\\EIS\\Component\\EIS'));
|
||||||
$container->registerServiceProvider(new MVCFactory('\\EIS\\Component\\EIS'));
|
$container->registerServiceProvider(new MVCFactory('\\EIS\\Component\\EIS'));
|
||||||
$container->registerServiceProvider(new RouterFactory('\\EIS\\Component\\EIS'));
|
$container->registerServiceProvider(new RouterFactory('\\EIS\\Component\\EIS'));
|
||||||
|
|
||||||
|
// DownloadController explizit registrieren
|
||||||
|
$container->set(
|
||||||
|
DownloadController::class,
|
||||||
|
fn(Container $c) => new DownloadController()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Komponentenschnittstelle
|
||||||
$container->set(
|
$container->set(
|
||||||
ComponentInterface::class,
|
ComponentInterface::class,
|
||||||
static fn(Container $c) => new MVCComponent(
|
static fn(Container $c) => new MVCComponent(
|
||||||
|
|||||||
62
com_eis/site/src/Controller/DownloadController.php
Normal file
62
com_eis/site/src/Controller/DownloadController.php
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
namespace EIS\Component\EIS\Site\Controller;
|
||||||
|
|
||||||
|
\defined('_JEXEC') or die;
|
||||||
|
|
||||||
|
use Joomla\CMS\Factory;
|
||||||
|
use Joomla\CMS\MVC\Controller\BaseController;
|
||||||
|
use Joomla\CMS\Router\Route;
|
||||||
|
use Joomla\Database\DatabaseDriver;
|
||||||
|
|
||||||
|
class DownloadController extends BaseController
|
||||||
|
{
|
||||||
|
public function download()
|
||||||
|
{
|
||||||
|
$app = Factory::getApplication();
|
||||||
|
$user = Factory::getUser();
|
||||||
|
$input = $app->input;
|
||||||
|
|
||||||
|
// Nur für eingeloggte Benutzer
|
||||||
|
if ($user->guest) {
|
||||||
|
$app->enqueueMessage('Bitte zuerst einloggen.', 'warning');
|
||||||
|
$app->redirect(Route::_('index.php?option=com_users&view=login', false));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID aus URL lesen
|
||||||
|
$id = $input->getInt('id');
|
||||||
|
if (!$id) {
|
||||||
|
throw new \RuntimeException("Keine Dokument-ID übergeben.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Datenbankabfrage
|
||||||
|
/** @var DatabaseDriver $db */
|
||||||
|
$db = Factory::getDbo();
|
||||||
|
|
||||||
|
$query = $db->getQuery(true)
|
||||||
|
->select($db->quoteName(['path', 'name']))
|
||||||
|
->from($db->quoteName('#__eis_documents'))
|
||||||
|
->where($db->quoteName('id') . ' = ' . (int) $id)
|
||||||
|
->where($db->quoteName('is_folder') . ' = 0');
|
||||||
|
|
||||||
|
$row = $db->setQuery($query)->loadAssoc();
|
||||||
|
|
||||||
|
if (!$row) {
|
||||||
|
throw new \RuntimeException("PDF nicht gefunden oder kein gültiges Dokument.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$filePath = $row['path'];
|
||||||
|
$fileName = $row['name'];
|
||||||
|
|
||||||
|
if (!file_exists($filePath)) {
|
||||||
|
throw new \RuntimeException("Datei existiert nicht auf dem Server.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// PDF-Datei ausgeben
|
||||||
|
header('Content-Type: application/pdf');
|
||||||
|
header('Content-Disposition: inline; filename="' . basename($fileName) . '"');
|
||||||
|
header('Content-Length: ' . filesize($filePath));
|
||||||
|
readfile($filePath);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,6 @@ namespace EIS\Component\EIS\Administrator\View\Main;
|
|||||||
\defined('_JEXEC') or die;
|
\defined('_JEXEC') or die;
|
||||||
use Joomla\CMS\Factory;
|
use Joomla\CMS\Factory;
|
||||||
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
|
||||||
|
|
||||||
class HtmlView extends BaseHtmlView
|
class HtmlView extends BaseHtmlView
|
||||||
{
|
{
|
||||||
public function display($tpl = null): void
|
public function display($tpl = null): void
|
||||||
|
|||||||
Binary file not shown.
@@ -9,7 +9,6 @@ class ModEisAnzeigeHelper
|
|||||||
/**
|
/**
|
||||||
* Holt alle PDF-Elemente aus der Datenbank
|
* Holt alle PDF-Elemente aus der Datenbank
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static function getItems(): array
|
public static function getItems(): array
|
||||||
{
|
{
|
||||||
/** @var DatabaseDriver $db */
|
/** @var DatabaseDriver $db */
|
||||||
@@ -35,7 +34,6 @@ class ModEisAnzeigeHelper
|
|||||||
/**
|
/**
|
||||||
* Hauptfunktion zum Rendern des Baums
|
* Hauptfunktion zum Rendern des Baums
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static function renderTree(array $items, int $parentId = null): string
|
public static function renderTree(array $items, int $parentId = null): string
|
||||||
{
|
{
|
||||||
if (!isset($items[$parentId])) {
|
if (!isset($items[$parentId])) {
|
||||||
@@ -47,19 +45,21 @@ class ModEisAnzeigeHelper
|
|||||||
foreach ($items[$parentId] as $item) {
|
foreach ($items[$parentId] as $item) {
|
||||||
$isFolder = (bool) $item['is_folder'];
|
$isFolder = (bool) $item['is_folder'];
|
||||||
$title = htmlspecialchars($item['title'] ?: $item['name']);
|
$title = htmlspecialchars($item['title'] ?: $item['name']);
|
||||||
// $path = htmlspecialchars($item['path'] ?? '');
|
$path = self::convertToRelativeUrl($item['path'] ?? '');
|
||||||
$path = htmlspecialchars(self::convertToRelativeUrl($item['path'] ?? ''));
|
|
||||||
|
// Erweiterung .pdf im Titel entfernen (nur Anzeige, nicht Link)
|
||||||
|
$displayTitle = preg_replace('/\.pdf$/i', '', $title);
|
||||||
|
|
||||||
if ($isFolder) {
|
if ($isFolder) {
|
||||||
$fileCount = self::countFilesRecursive($items, $item['id']);
|
$fileCount = self::countFilesRecursive($items, $item['id']);
|
||||||
$html .= '<li class="folder">';
|
$html .= '<li class="folder">';
|
||||||
$html .= '<span class="toggle">▶</span>';
|
$html .= '<span class="toggle">▶</span>';
|
||||||
$html .= '<span class="folder-icon"></span>' . $title . ' <small>(' . $fileCount . ')</small>';
|
$html .= '<span class="folder-icon">📁</span> ' . $displayTitle . ' <small>(' . $fileCount . ')</small>';
|
||||||
$html .= self::renderTree($items, $item['id']);
|
$html .= self::renderTree($items, $item['id']);
|
||||||
$html .= '</li>';
|
$html .= '</li>';
|
||||||
} else {
|
} else {
|
||||||
$html .= '<li class="file">';
|
$html .= '<li class="file">';
|
||||||
$html .= '<span class="file-icon"></span><a class="file-link" href="' . $path . '">' . $title . '</a>';
|
$html .= '<span class="file-icon">📄</span><a class="file-link" href="' . htmlspecialchars($path) . '" title="' . $title . '">' . $displayTitle . '</a>';
|
||||||
$html .= '</li>';
|
$html .= '</li>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,22 +68,25 @@ class ModEisAnzeigeHelper
|
|||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Konvertiert absoluten Serverpfad in URL
|
* Konvertiert absoluten Serverpfad in URL
|
||||||
*/
|
*/
|
||||||
private static function convertToRelativeUrl(string $fullPath): string
|
private static function convertToRelativeUrl(string $fullPath): string
|
||||||
{
|
{
|
||||||
// <== HIER den absoluten Pfad zu deinem Webroot anpassen
|
// Absoluter Serverpfad zum Joomla-Root
|
||||||
$webRoot = '/var/www/vhosts/ts-it24.net/stbv.ts-it24.net';
|
$webRoot = '/var/www/joomla';
|
||||||
$webBase = ''; // ggf. '/subdir' falls Joomla in Unterordner
|
$webBase = ''; // ggf. '/unterordner', wenn Joomla in Subdir
|
||||||
|
|
||||||
if (str_starts_with($fullPath, $webRoot)) {
|
if (str_starts_with($fullPath, $webRoot)) {
|
||||||
return $webBase . str_replace($webRoot, '', $fullPath);
|
$relativePath = str_replace($webRoot, '', $fullPath);
|
||||||
|
// Leerzeichen und Sonderzeichen escapen
|
||||||
|
$relativePath = implode('/', array_map('rawurlencode', explode('/', $relativePath)));
|
||||||
|
return rtrim(\JUri::root(), '/') . $webBase . $relativePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $fullPath; // Fallback: Original verwenden
|
return $fullPath; // Fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zählt alle PDF-Dateien unterhalb eines Ordners rekursiv
|
* Zählt alle PDF-Dateien unterhalb eines Ordners rekursiv
|
||||||
*/
|
*/
|
||||||
@@ -96,7 +99,7 @@ class ModEisAnzeigeHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($items[$parentId] as $item) {
|
foreach ($items[$parentId] as $item) {
|
||||||
if ((bool)$item['is_folder']) {
|
if ((bool) $item['is_folder']) {
|
||||||
$count += self::countFilesRecursive($items, $item['id']);
|
$count += self::countFilesRecursive($items, $item['id']);
|
||||||
} else {
|
} else {
|
||||||
$count++;
|
$count++;
|
||||||
|
|||||||
BIN
mod_pdf_tree/mod_eis_anzeige.zip
Normal file
BIN
mod_pdf_tree/mod_eis_anzeige.zip
Normal file
Binary file not shown.
@@ -1,8 +1,6 @@
|
|||||||
<?php defined('_JEXEC') or die; ?>
|
<?php defined('_JEXEC') or die; ?>
|
||||||
|
|
||||||
<!-- Styles für Struktur, Vorschau und Icons -->
|
|
||||||
<style>
|
<style>
|
||||||
/* Baum und Vorschau nebeneinander */
|
|
||||||
.pdf-tree-wrapper {
|
.pdf-tree-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
@@ -12,16 +10,16 @@
|
|||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
box-shadow: 0 4px 10px rgba(0,0,0,0.05);
|
box-shadow: 0 4px 10px rgba(0,0,0,0.05);
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%; /* Oder: max-width: 1400px; */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Linke Spalte: Verzeichnisbaum */
|
|
||||||
.pdf-tree-container {
|
.pdf-tree-container {
|
||||||
flex: 0 0 30%;
|
flex: 0 0 30%;
|
||||||
height: 95vh;
|
max-height: 95vh;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Vorschaufenster rechts */
|
|
||||||
#pdf-preview {
|
#pdf-preview {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 800px;
|
min-width: 800px;
|
||||||
@@ -31,50 +29,46 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Vorschau-Inhalt (PDF) */
|
|
||||||
#pdf-preview iframe {
|
#pdf-preview iframe {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Verzeichnisliste zurücksetzen */
|
.pdf-tree {
|
||||||
.pdf-tree, .pdf-tree ul {
|
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
.pdf-tree ul {
|
||||||
|
list-style: none;
|
||||||
|
margin-left: 1.5em;
|
||||||
|
padding: 0;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.pdf-tree li {
|
.pdf-tree li {
|
||||||
margin: 0.3em 0;
|
margin: 0.3em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ordner-Icons & Pfeile */
|
|
||||||
.folder > .toggle {
|
.folder > .toggle {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: inline-block;
|
|
||||||
width: 1em;
|
width: 1em;
|
||||||
}
|
display: inline-block;
|
||||||
.folder-icon::before {
|
user-select: none;
|
||||||
content: "📁";
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Datei-Icon */
|
/* Optionale visuelle Trennung bei Dateien */
|
||||||
.file-icon::before {
|
.file-link {
|
||||||
content: "📄";
|
text-decoration: none;
|
||||||
margin-right: 4px;
|
color: #0366d6;
|
||||||
|
}
|
||||||
|
.file-link:hover {
|
||||||
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Standard: Unterverzeichnisse einklappen */
|
|
||||||
.pdf-tree ul {
|
|
||||||
display: none;
|
|
||||||
margin-left: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Buttons oben */
|
|
||||||
.expand-collapse {
|
.expand-collapse {
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
@@ -83,68 +77,59 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- Steuerbuttons oben -->
|
<!-- Buttons: Aus-/Einklappen -->
|
||||||
<div class="expand-collapse">
|
<div class="expand-collapse">
|
||||||
<button id="expand-all">ausklappen</button>
|
<button id="expand-all">ausklappen</button>
|
||||||
<button id="collapse-all">einklappen</button>
|
<button id="collapse-all">einklappen</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- PDF-Baum und Vorschau -->
|
||||||
<div class="pdf-tree-wrapper">
|
<div class="pdf-tree-wrapper">
|
||||||
<!-- Links: Verzeichnisbaum -->
|
|
||||||
<div class="pdf-tree-container">
|
<div class="pdf-tree-container">
|
||||||
<?php echo ModEisAnzeigeHelper::renderTree($items); ?>
|
<?= ModEisAnzeigeHelper::renderTree($items); ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Rechts: Vorschau-Bereich -->
|
|
||||||
<div id="pdf-preview"></div>
|
<div id="pdf-preview"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Interaktivität: Vorschau, Toggle, Buttons -->
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const preview = document.getElementById('pdf-preview');
|
||||||
|
if (!preview) return;
|
||||||
|
|
||||||
// (1) Verzeichnisse auf-/zuklappen per Klick
|
// (1) Verzeichnisse toggeln
|
||||||
document.querySelectorAll('.pdf-tree .toggle').forEach(function(toggle) {
|
document.querySelectorAll('.pdf-tree .toggle').forEach(toggle => {
|
||||||
toggle.addEventListener('click', function() {
|
toggle.addEventListener('click', () => {
|
||||||
var li = this.parentNode;
|
const ul = toggle.closest('li').querySelector('ul');
|
||||||
var ul = li.querySelector('ul');
|
if (ul) {
|
||||||
if (!ul) return;
|
const visible = ul.style.display === 'block';
|
||||||
if (ul.style.display === 'block') {
|
ul.style.display = visible ? 'none' : 'block';
|
||||||
ul.style.display = 'none'; this.textContent = '▶';
|
toggle.textContent = visible ? '▶' : '▼';
|
||||||
} else {
|
|
||||||
ul.style.display = 'block'; this.textContent = '▼';
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// (2) Alle ausklappen
|
// (2) Alle ausklappen
|
||||||
document.getElementById('expand-all').addEventListener('click', function() {
|
document.getElementById('expand-all')?.addEventListener('click', () => {
|
||||||
document.querySelectorAll('.pdf-tree ul').forEach(function(ul) {
|
document.querySelectorAll('.pdf-tree ul').forEach(ul => ul.style.display = 'block');
|
||||||
ul.style.display = 'block';
|
document.querySelectorAll('.pdf-tree .toggle').forEach(t => t.textContent = '▼');
|
||||||
});
|
|
||||||
document.querySelectorAll('.pdf-tree .toggle').forEach(function(toggle) {
|
|
||||||
toggle.textContent = '▼';
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// (3) Alle einklappen
|
// (3) Alle einklappen
|
||||||
document.getElementById('collapse-all').addEventListener('click', function() {
|
document.getElementById('collapse-all')?.addEventListener('click', () => {
|
||||||
document.querySelectorAll('.pdf-tree ul').forEach(function(ul) {
|
document.querySelectorAll('.pdf-tree ul').forEach(ul => ul.style.display = 'none');
|
||||||
ul.style.display = 'none';
|
document.querySelectorAll('.pdf-tree .toggle').forEach(t => t.textContent = '▶');
|
||||||
});
|
|
||||||
document.querySelectorAll('.pdf-tree .toggle').forEach(function(toggle) {
|
|
||||||
toggle.textContent = '▶';
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// (4) Vorschau anzeigen beim Klick
|
// (4) PDF-Vorschau
|
||||||
var preview = document.getElementById('pdf-preview');
|
document.querySelectorAll('.pdf-tree .file-link').forEach(link => {
|
||||||
document.querySelectorAll('.pdf-tree .file-link').forEach(function(link) {
|
link.addEventListener('click', e => {
|
||||||
link.addEventListener('click', function(e) {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
preview.style.display = 'block';
|
preview.style.display = 'block';
|
||||||
preview.innerHTML = '<iframe src="' + this.href + '" loading="lazy"></iframe>';
|
preview.innerHTML = ''; // Vorherige Vorschau entfernen
|
||||||
|
const iframe = document.createElement('iframe');
|
||||||
|
iframe.src = link.href;
|
||||||
|
iframe.loading = 'lazy';
|
||||||
|
preview.appendChild(iframe);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user