DolEditor für Notiz + Notiz unter Bild + Hack-Font im PDF [deploy]
All checks were successful
Deploy bericht / deploy (push) Successful in 1s

- bericht_card.php: Plain-Textarea durch DolEditor (CKEditor, dolibarr_notes-Toolbar)
  ersetzt, damit Notizen formatiert werden können.
- editor.js: getNoteValue()/setNoteValue() Helper für transparentes
  CKEditor/Textarea-Handling an allen Zugriffsstellen.
- lib/bericht.lib.php:
  * bericht_write_note_html() rendert CKEditor-HTML via TCPDF::writeHTMLCell
  * Composite-Branch: Notiz direkt unter dem Bild statt mit SetY(-20) unten
  * bericht_ensure_hack_font() registriert Hack-TTFs beim ersten PDF-Run
  * Alle helvetica-SetFont-Calls auf Hack umgestellt (Corporate-Font)
- fonts/: Hack-Regular/Bold/Italic/BoldItalic.ttf (Eddys Corporate-Font)
- bericht_batch.php: ebenfalls Hack-Font
This commit is contained in:
Eduard Wisch 2026-04-09 15:25:10 +02:00
parent 9c7ef73061
commit 021ef1cbb2
8 changed files with 109 additions and 29 deletions

View file

@ -60,14 +60,14 @@ if ($action === 'generate') {
// Inhaltsverzeichnis-Seite
$pdf->AddPage('P', 'A4');
$pdf->SetFont('helvetica', 'B', 18);
$pdf->SetFont(bericht_ensure_hack_font(), 'B', 18);
$pdf->Cell(0, 12, 'Bericht-Sammlung', 0, 1, 'C');
$pdf->SetFont('helvetica', '', 11);
$pdf->SetFont(bericht_ensure_hack_font(), '', 11);
$pdf->Cell(0, 8, 'Erstellt: '.dol_print_date(dol_now(), 'dayhour'), 0, 1, 'C');
$pdf->Ln(8);
$pdf->SetFont('helvetica', 'B', 13);
$pdf->SetFont(bericht_ensure_hack_font(), 'B', 13);
$pdf->Cell(0, 8, 'Enthaltene Berichte ('.count($ids).')', 0, 1, 'L');
$pdf->SetFont('helvetica', '', 10);
$pdf->SetFont(bericht_ensure_hack_font(), '', 10);
$berichte = array();
foreach ($ids as $id) {

View file

@ -499,7 +499,10 @@ if (!$bericht) {
print '</div>';
print '<div class="bericht-page-note">';
print '<label>'.$langs->trans("BerichtNoteHint").'</label>';
print '<textarea id="page-note" rows="2"></textarea>';
// DolEditor (CKEditor) — wird im PDF mit writeHTMLCell gerendert
require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
$noteEditor = new DolEditor('page-note', '', '100%', 120, 'dolibarr_notes', 'In', false, true, true, 4, '100%');
$noteEditor->Create(0);
print '</div>';
print '</main>';

BIN
fonts/Hack-Bold.ttf Normal file

Binary file not shown.

BIN
fonts/Hack-BoldItalic.ttf Normal file

Binary file not shown.

BIN
fonts/Hack-Italic.ttf Normal file

Binary file not shown.

BIN
fonts/Hack-Regular.ttf Normal file

Binary file not shown.

View file

@ -26,6 +26,29 @@
const cfg = window.BERICHT_CONFIG || {};
if (!cfg.berichtid) { console.warn('Bericht: keine Konfiguration'); return; }
/**
* Liest den Notiz-Text aus funktioniert mit CKEditor (DolEditor) UND plain textarea
*/
function getNoteValue() {
if (window.CKEDITOR && window.CKEDITOR.instances && window.CKEDITOR.instances['page-note']) {
return window.CKEDITOR.instances['page-note'].getData() || '';
}
const el = document.getElementById('page-note');
return el ? el.value : '';
}
/**
* Setzt den Notiz-Text.
*/
function setNoteValue(html) {
if (window.CKEDITOR && window.CKEDITOR.instances && window.CKEDITOR.instances['page-note']) {
window.CKEDITOR.instances['page-note'].setData(html || '');
return;
}
const el = document.getElementById('page-note');
if (el) el.value = html || '';
}
// PDF.js worker (lokal)
if (window.pdfjsLib) {
pdfjsLib.GlobalWorkerOptions.workerSrc = '/bericht/js/lib/pdf.worker.min.js';
@ -157,7 +180,7 @@
if (wrapL) wrapL.classList.remove('empty'); // wird gleich aus loadPageMeta überschrieben falls gespeichert
fabricCanvas.clear();
document.getElementById('page-note').value = '';
setNoteValue('');
await loadPageMeta(); // setzt currentPageRotation + ggf. loadedFabricJson
@ -354,7 +377,7 @@
if (!r.ok) return;
const data = await r.json();
if (data.fabric_json) loadedFabricJson = data.fabric_json;
if (data.note) document.getElementById('page-note').value = data.note;
if (data.note) setNoteValue(data.note);
if (typeof data.rotation !== 'undefined' && data.rotation !== null) {
currentPageRotation = parseInt(data.rotation, 10) || 0;
}
@ -745,7 +768,7 @@
fd.append('token', cfg.token);
fd.append('pageid', currentPageId);
fd.append('fabric_json', JSON.stringify(fabricCanvas.toJSON(['bgImage'])));
fd.append('note', document.getElementById('page-note').value || '');
fd.append('note', getNoteValue() || '');
fd.append('rotation', currentPageRotation);
// Phase 6: Composite-PNG

View file

@ -276,7 +276,7 @@ function bericht_burn_annotations($pdf, $fabric_json, $x, $y, $w, $h)
case 'text':
case 'textbox':
$fontsize = max(6, ($obj['fontSize'] ?? 16) * $sx * 2.83);
$pdf->SetFont('helvetica', '', $fontsize);
$pdf->SetFont(bericht_ensure_hack_font(), '', $fontsize);
$pdf->SetTextColor($stroke[0], $stroke[1], $stroke[2]);
$pdf->Text($ox, $oy + $fontsize * 0.35, $obj['text'] ?? '');
break;
@ -305,10 +305,64 @@ function bericht_render_cover_for_preview($template_path, $bericht, $parent, $te
* @param string $fmt A4/A3/A5/Letter
* @param bool $fpdi_loaded
*/
/**
* Registriert den Hack-Font (Eddys Corporate-Font) in TCPDF und gibt den Font-Key zurück.
* Konvertiert die TTFs beim ersten Aufruf via TCPDF_FONTS::addTTFfont ins TCPDF-Font-Verzeichnis.
* Fallback auf 'helvetica' wenn etwas schiefgeht.
*
* @return string Font-Key für $pdf->SetFont()
*/
function bericht_ensure_hack_font()
{
static $cached = null;
if ($cached !== null) return $cached;
if (!class_exists('TCPDF_FONTS')) {
$cached = 'helvetica';
return $cached;
}
$dir = dirname(__DIR__).'/fonts';
$files = array(
'' => $dir.'/Hack-Regular.ttf',
'B' => $dir.'/Hack-Bold.ttf',
'I' => $dir.'/Hack-Italic.ttf',
'BI' => $dir.'/Hack-BoldItalic.ttf',
);
try {
$key = null;
foreach ($files as $style => $path) {
if (!file_exists($path)) continue;
$k = TCPDF_FONTS::addTTFfont($path, 'TrueTypeUnicode', '', 32);
if ($style === '' && $k) $key = $k;
}
$cached = $key ?: 'helvetica';
} catch (Throwable $e) {
$cached = 'helvetica';
}
return $cached;
}
/**
* Rendert eine HTML-Notiz (CKEditor-Output) mit TCPDF::writeHTMLCell
* in einen reservierten Bereich unterhalb des Bildes.
*/
function bericht_write_note_html($pdf, $html, $x, $y, $w, $h)
{
if (empty($html)) return;
// CKEditor liefert <p>…</p> — TCPDF kann das direkt
$pdf->SetFont(bericht_ensure_hack_font(), '', 9);
$pdf->SetTextColor(40, 40, 40);
// Border 0, kein Auto-Pagebreak damit die Notiz im reservierten Bereich bleibt
$autoPB = $pdf->getAutoPageBreak();
$bMargin = $pdf->getBreakMargin();
$pdf->SetAutoPageBreak(false, 0);
$pdf->writeHTMLCell($w, $h, $x, $y, $html, 0, 1, false, true, 'L', true);
$pdf->SetAutoPageBreak($autoPB, $bMargin);
}
function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded)
{
// Phase 6: Wenn der Editor ein Composite-PNG hochgeladen hat, nutzen wir das
// direkt — ein Bild über die ganze Seite. Keine Server-Shape-Logik nötig.
// Phase 6: Wenn der Editor ein Composite-PNG hochgeladen hat, nutzen wir das direkt
if (!empty($page->composite_path)) {
$full = bericht_resolve_data_path($page->composite_path);
if ($full && file_exists($full)) {
@ -316,8 +370,14 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded)
$pageW = $pdf->getPageWidth();
$pageH = $pdf->getPageHeight();
$margin = 10;
// Notiz-Bereich reservieren wenn eine Notiz existiert
$note_h = 0;
if (!empty($page->note)) {
// ca. 1/4 Seite für HTML-Notizen, aber mindestens 20mm, max 80mm
$note_h = max(20, min(80, $pageH * 0.25));
}
$maxW = $pageW - 2 * $margin;
$maxH = $pageH - 2 * $margin - (empty($page->note) ? 0 : 10);
$maxH = $pageH - 2 * $margin - $note_h - ($note_h ? 4 : 0);
list($iw, $ih) = @getimagesize($full);
if ($iw && $ih) {
$ratio = min($maxW / $iw, $maxH / $ih);
@ -327,9 +387,9 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded)
$pdf->Image($full, $x, $y, $w, $h);
}
if (!empty($page->note)) {
$pdf->SetY(-20);
$pdf->SetFont('helvetica', 'I', 9);
$pdf->MultiCell(0, 5, $page->note, 0, 'L');
// Notiz direkt unter dem Bild rendern — kein SetY(-20), keine auto-Page-Break
$note_y = $margin + ($ih && $iw ? ($ih * min($maxW / $iw, $maxH / $ih)) : $maxH) + 4;
bericht_write_note_html($pdf, $page->note, $margin, $note_y, $maxW, $note_h);
}
return;
}
@ -342,13 +402,13 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded)
$pdf->AddPage($ori, $fmt);
$pageW = $pdf->getPageWidth();
$pageH = $pdf->getPageHeight();
$pdf->SetFont('helvetica', 'B', 32);
$pdf->SetFont(bericht_ensure_hack_font(), 'B', 32);
$pdf->SetTextColor(40, 40, 40);
$pdf->SetY($pageH / 2 - 20);
$pdf->MultiCell(0, 20, $page->title, 0, 'C');
if (!empty($page->note)) {
$pdf->Ln(12);
$pdf->SetFont('helvetica', '', 12);
$pdf->SetFont(bericht_ensure_hack_font(), '', 12);
$pdf->MultiCell(0, 8, $page->note, 0, 'C');
}
return;
@ -364,7 +424,7 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded)
$margin = 10;
$title_h = !empty($page->title) ? 12 : 0;
if ($title_h) {
$pdf->SetFont('helvetica', 'B', 16);
$pdf->SetFont(bericht_ensure_hack_font(), 'B', 16);
$pdf->SetY($margin);
$pdf->MultiCell(0, $title_h, $page->title, 0, 'C');
}
@ -385,7 +445,7 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded)
$x0 = $margin + $slot * ($w_each + $gap);
// Label
$pdf->SetFont('helvetica', 'B', 11);
$pdf->SetFont(bericht_ensure_hack_font(), 'B', 11);
$pdf->SetXY($x0, $top);
$pdf->Cell($w_each, $label_h, $label, 0, 0, 'C');
// Bild darunter
@ -397,9 +457,7 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded)
}
bericht_burn_annotations($pdf, $page->fabric_json, 0, 0, $pageW, $pageH);
if (!empty($page->note)) {
$pdf->SetY(-20);
$pdf->SetFont('helvetica', 'I', 9);
$pdf->MultiCell(0, 5, $page->note, 0, 'L');
bericht_write_note_html($pdf, $page->note, 10, $pdf->getPageHeight() - 22, $pdf->getPageWidth() - 20, 18);
}
return;
}
@ -416,7 +474,7 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded)
// Titel oben
$title_h = 0;
if (!empty($page->title)) {
$pdf->SetFont('helvetica', 'B', 16);
$pdf->SetFont(bericht_ensure_hack_font(), 'B', 16);
$pdf->SetY(10);
$pdf->MultiCell(0, 10, $page->title, 0, 'C');
$title_h = 14;
@ -443,9 +501,7 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded)
// Notiz unten
if (!empty($page->note)) {
$pdf->SetY(-20);
$pdf->SetFont('helvetica', 'I', 9);
$pdf->MultiCell(0, 5, $page->note, 0, 'L');
bericht_write_note_html($pdf, $page->note, 10, $pdf->getPageHeight() - 22, $pdf->getPageWidth() - 20, 18);
}
return;
}
@ -489,9 +545,7 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded)
}
if (!empty($page->note)) {
$pdf->SetY(-20);
$pdf->SetFont('helvetica', 'I', 9);
$pdf->MultiCell(0, 5, $page->note, 0, 'L');
bericht_write_note_html($pdf, $page->note, 10, $pdf->getPageHeight() - 22, $pdf->getPageWidth() - 20, 18);
}
}