From 771cfb5611c7ae1f777511466703c63f21ce902a Mon Sep 17 00:00:00 2001 From: riyadhafraa <49757212-riyadhafraa@users.noreply.replit.com> Date: Mon, 4 May 2026 09:24:37 +0000 Subject: [PATCH] Improve PDF generation for meeting tables with better text handling Update PDF rendering logic to correctly handle bidirectional text, cell merging, and text wrapping for meeting tables. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 36ae937b-a1fc-4edb-8901-b07ed7713220 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/Zh9QhRk Replit-Helium-Checkpoint-Created: true --- artifacts/api-server/src/lib/pdf-renderer.ts | 270 +++++++++++++----- .../src/routes/executive-meetings.ts | 6 +- artifacts/tx-os/public/opengraph.jpg | Bin 25969 -> 25910 bytes ...--PDF-PDF--1777885005658_1777885005659.txt | 151 ++++++++++ 4 files changed, 354 insertions(+), 73 deletions(-) create mode 100644 attached_assets/Pasted--PDF-PDF--1777885005658_1777885005659.txt diff --git a/artifacts/api-server/src/lib/pdf-renderer.ts b/artifacts/api-server/src/lib/pdf-renderer.ts index b8cec909..79698f9a 100644 --- a/artifacts/api-server/src/lib/pdf-renderer.ts +++ b/artifacts/api-server/src/lib/pdf-renderer.ts @@ -88,11 +88,12 @@ export type PdfMeeting = { startTime: string | null; endTime: string | null; location: string | null; - // Legacy field; ignored by renderer (use rowColor instead). isHighlighted?: number; - // Palette key from ROW_COLOR_FILL; unknown/null = no tint. rowColor?: string | null; attendees: PdfMeetingAttendee[]; + mergeStartColumn?: string | null; + mergeEndColumn?: string | null; + mergeText?: string | null; }; export type RenderPdfInput = { @@ -483,10 +484,65 @@ type DrawOpts = { lineHeight?: number; }; -// Draw a single line of text using mixed Arabic/Latin runs (in visual -// order). We measure each run with the right font and lay them out -// left-to-right starting from the resolved alignment. Returns the height -// consumed by this line (including a small line-gap). +const BIDI_CONTROL_RE = /[\u200E\u200F\u200B\u202A-\u202E\u2066-\u2069]/g; +function stripBidiControls(s: string): string { + return s.replace(BIDI_CONTROL_RE, ""); +} + +function measureBidiLineWidth( + doc: PDFKit.PDFDocument, + text: string, + opts: Pick, +): number { + const runs = visualOrderRuns(text, opts.baseDirection); + let w = 0; + for (const r of runs) { + const clean = stripBidiControls(r.text); + if (!clean) continue; + const fk = fontKeyFor(r.isArabic, opts.weight, opts.mapping); + const features = featuresFor(r.isArabic); + doc.font(fk).fontSize(opts.fontSize); + w += doc.widthOfString(clean, features ? { features } : {}); + } + return w; +} + +function drawBidiLine( + doc: PDFKit.PDFDocument, + text: string, + opts: DrawOpts, +): void { + const runs = visualOrderRuns(text, opts.baseDirection); + if (runs.length === 0) return; + let totalWidth = 0; + const measured: { clean: string; isArabic: boolean; width: number; fontKey: string; features: PDFKit.Mixins.OpenTypeFeatures[] | undefined }[] = []; + for (const r of runs) { + const clean = stripBidiControls(r.text); + if (!clean) continue; + const fk = fontKeyFor(r.isArabic, opts.weight, opts.mapping); + const features = featuresFor(r.isArabic); + doc.font(fk).fontSize(opts.fontSize); + const w = doc.widthOfString(clean, features ? { features } : {}); + totalWidth += w; + measured.push({ clean, isArabic: r.isArabic, width: w, fontKey: fk, features }); + } + let cursorX = opts.x; + if (opts.align === "center") { + cursorX = opts.x + Math.max(0, (opts.width - totalWidth) / 2); + } else if (opts.align === "right") { + cursorX = opts.x + Math.max(0, opts.width - totalWidth); + } + for (const r of measured) { + doc.font(r.fontKey).fontSize(opts.fontSize).fillColor(opts.color ?? "black"); + doc.text(r.clean, cursorX, opts.y, { + lineBreak: false, + width: r.width + 1, + ...(r.features ? { features: [...r.features] } : {}), + }); + cursorX += r.width; + } +} + function drawMixedLine( doc: PDFKit.PDFDocument, text: string, @@ -497,8 +553,6 @@ function drawMixedLine( if (runs.length === 0) { return lh; } - // Measure full line width — feature flags must match the draw call so - // ligatures + RTL alternates produce the same advance width. let totalWidth = 0; const measured = runs.map((r) => { const fk = fontKeyFor(r.isArabic, opts.weight, opts.mapping); @@ -508,19 +562,15 @@ function drawMixedLine( totalWidth += w; return { ...r, width: w, fontKey: fk, features }; }); - const overflow = totalWidth - opts.width; + if (totalWidth > opts.width + 4) { + return drawWrappingLine(doc, text, opts); + } let cursorX = opts.x; if (opts.align === "center") { cursorX = opts.x + Math.max(0, (opts.width - totalWidth) / 2); } else if (opts.align === "right") { cursorX = opts.x + Math.max(0, opts.width - totalWidth); } - // If we overflow horizontally, fall back to wrapping via PDFKit's own - // text engine on the first run. Cells in the schedule rarely overflow - // because column widths are generous, but Arabic titles can be long. - if (overflow > 4) { - return drawWrappingLine(doc, text, opts); - } for (const r of measured) { doc.font(r.fontKey).fontSize(opts.fontSize).fillColor(opts.color ?? "black"); doc.text(r.text, cursorX, opts.y, { @@ -538,32 +588,60 @@ function drawWrappingLine( text: string, opts: DrawOpts, ): number { - // Determine the dominant script for the wrapping pass. Without true - // bidi line-breaking we pick the "majority" script font to wrap with; - // this keeps shaping intact for the dominant direction at the cost of - // a slight metric mismatch on the minority runs. - const arabicChars = [...text].filter(isArabicChar).length; - const dominantArabic = arabicChars * 2 > text.length; - const fk = fontKeyFor(dominantArabic, opts.weight, opts.mapping); - doc.font(fk).fontSize(opts.fontSize).fillColor(opts.color ?? "black"); - // Hand the RAW (logical-order) string to pdfkit and let fontkit do - // both Arabic shaping and intra-line RTL reorder via the `features` - // option. Pre-shaping here would double-process the string and - // produce visually-mirrored output (the bug we shipped previously). - const features = featuresFor(dominantArabic); - const before = doc.y; - doc.text(text, opts.x, opts.y, { - width: opts.width, - align: opts.align, - lineBreak: true, - // Tighten the inter-line gap pdfkit applies inside wrapped paragraphs. - // Default is the font's natural lineGap; setting -1 saves ~1pt per - // wrapped line which matters when fitting a full day on one page. - lineGap: -1, - ...(features ? { features } : {}), - }); - const wrapLh = opts.lineHeight ?? opts.fontSize * 1.2; - return Math.max(wrapLh, doc.y - before); + const lh = opts.lineHeight ?? opts.fontSize * 1.2; + if (!text.trim()) return lh; + const words = text.split(/\s+/).filter((w) => w.length > 0); + if (words.length === 0) return lh; + const mOpts = { + fontSize: opts.fontSize, + weight: opts.weight, + baseDirection: opts.baseDirection, + mapping: opts.mapping, + }; + const hardBreak = (word: string): string[] => { + const ww = measureBidiLineWidth(doc, word, mOpts); + if (ww <= opts.width) return [word]; + const chars = [...word]; + const pieces: string[] = []; + let cur = ""; + for (const ch of chars) { + const test = cur + ch; + if (cur && measureBidiLineWidth(doc, test, mOpts) > opts.width) { + pieces.push(cur); + cur = ch; + } else { + cur = test; + } + } + if (cur) pieces.push(cur); + return pieces; + }; + + const visualLines: string[] = []; + let current = ""; + for (let i = 0; i < words.length; i++) { + const ww = measureBidiLineWidth(doc, words[i], mOpts); + if (ww > opts.width) { + if (current) { visualLines.push(current); current = ""; } + for (const piece of hardBreak(words[i])) visualLines.push(piece); + continue; + } + const test = current ? current + " " + words[i] : words[i]; + if (measureBidiLineWidth(doc, test, mOpts) > opts.width) { + visualLines.push(current); + current = words[i]; + } else { + current = test; + } + } + if (current) visualLines.push(current); + if (visualLines.length === 0) return lh; + let totalH = 0; + for (const vl of visualLines) { + drawBidiLine(doc, vl, { ...opts, y: opts.y + totalH }); + totalH += lh; + } + return Math.max(lh, totalH); } export async function renderSchedulePdf(input: RenderPdfInput): Promise { @@ -757,9 +835,13 @@ export async function renderSchedulePdf(input: RenderPdfInput): Promise const headerHeight = drawHeader(); doc.y = startY + headerHeight; + const MERGE_COL_INDEX: Record = { + number: 0, meeting: 1, attendees: 2, time: 3, + }; + // ---- Rows ---- for (const meeting of input.meetings) { - const cellsLogical: { text: string; align: "left" | "center" | "right" }[] = [ + let cellsLogical: { text: string; align: "left" | "center" | "right" }[] = [ { text: String(meeting.dailyNumber), align: "center" }, { text: htmlToPlain(isRtl ? meeting.titleAr : meeting.titleEn || meeting.titleAr) + @@ -771,28 +853,31 @@ export async function renderSchedulePdf(input: RenderPdfInput): Promise meeting.attendees.length === 0 ? "—" : (() => { + const ATTENDEES_PER_LINE = 3; let personIdx = 0; const parts: string[] = []; let currentGroup: string[] = []; + const flushGroup = () => { + if (currentGroup.length === 0) return; + for (let i = 0; i < currentGroup.length; i += ATTENDEES_PER_LINE) { + parts.push(currentGroup.slice(i, i + ATTENDEES_PER_LINE).join(" ")); + } + currentGroup = []; + }; for (const a of meeting.attendees) { const isSub = (a.kind ?? "person") === "subheading"; const name = htmlToPlain(a.name); if (isSub) { - if (currentGroup.length > 0) { - parts.push(currentGroup.join(" ")); - } + flushGroup(); personIdx = 0; parts.push(`— ${name} —`); - currentGroup = []; } else { personIdx += 1; const t = a.title?.trim(); - currentGroup.push(`-${personIdx} ${name}${t ? ` (${t})` : ""}`); + currentGroup.push(`\u202A${personIdx}-\u202C ${name}${t ? ` (${t})` : ""}`); } } - if (currentGroup.length > 0) { - parts.push(currentGroup.join(" ")); - } + flushGroup(); return parts.join("\n"); })(), align: "center", @@ -802,8 +887,29 @@ export async function renderSchedulePdf(input: RenderPdfInput): Promise align: "center", }, ]; + let cellWidths = [...colWidths]; + + if (meeting.mergeStartColumn && meeting.mergeEndColumn) { + const startIdx = MERGE_COL_INDEX[meeting.mergeStartColumn]; + const endIdx = MERGE_COL_INDEX[meeting.mergeEndColumn]; + if (startIdx !== undefined && endIdx !== undefined && startIdx <= endIdx) { + const mergedWidth = cellWidths.slice(startIdx, endIdx + 1).reduce((a, b) => a + b, 0); + const mergedCell = { text: meeting.mergeText ? htmlToPlain(meeting.mergeText) : "", align: "center" as const }; + cellsLogical = [ + ...cellsLogical.slice(0, startIdx), + mergedCell, + ...cellsLogical.slice(endIdx + 1), + ]; + cellWidths = [ + ...cellWidths.slice(0, startIdx), + mergedWidth, + ...cellWidths.slice(endIdx + 1), + ]; + } + } + const cells = isRtl ? [...cellsLogical].reverse() : cellsLogical; - const widths = isRtl ? [...colWidths].reverse() : colWidths; + const widths = isRtl ? [...cellWidths].reverse() : cellWidths; // Measure the row height by laying out each cell to a temporary // y-cursor and taking the max. We then redraw at the final position. @@ -812,16 +918,16 @@ export async function renderSchedulePdf(input: RenderPdfInput): Promise let rowHeight = lineHeight + cellPadY * 2; const cellHeights: number[] = []; let cx = tableX; + const probeWrapOpts = { + fontSize: input.font.fontSize, + weight: input.font.fontWeight, + baseDirection: baseDir, + mapping, + }; for (let i = 0; i < cells.length; i++) { const c = cells[i]; const startProbeY = probeY + cellPadY; probe.y = startProbeY; - // Use PDFKit's own layout engine (heightOfString) so the probe - // reserves EXACTLY as much vertical space as the eventual draw - // call will consume — passing the same font, features, width, - // and align as drawWrappingLine. A heuristic ceil(w/availableW) - // probe under-counts whenever pdfkit's word-break engine wraps - // sooner than a simple division would, causing rows to overlap. const lines = c.text.split("\n"); let h = 0; const cellW = widths[i] - cellPadX * 2; @@ -830,19 +936,43 @@ export async function renderSchedulePdf(input: RenderPdfInput): Promise h += lineHeight; continue; } - const lineArabicChars = [...line].filter(isArabicChar).length; - const lineDominantArabic = lineArabicChars * 2 > line.length; - const lineFk = fontKeyFor(lineDominantArabic, input.font.fontWeight, mapping); - const lineFeatures = featuresFor(lineDominantArabic); - doc.font(lineFk).fontSize(input.font.fontSize); - const measured = doc.heightOfString(line, { - width: cellW, - align: c.align, - lineBreak: true, - lineGap: -1, - ...(lineFeatures ? { features: lineFeatures } : {}), - }); - h += Math.max(lineHeight, measured); + const singleW = measureBidiLineWidth(doc, line, probeWrapOpts); + if (singleW <= cellW) { + h += lineHeight; + } else { + const wds = line.split(/\s+/).filter((w: string) => w.length > 0); + if (wds.length === 0) { h += lineHeight; continue; } + let wrapCount = 0; + let cur = ""; + for (let wi = 0; wi < wds.length; wi++) { + const wordW = measureBidiLineWidth(doc, wds[wi], probeWrapOpts); + if (wordW > cellW) { + if (cur) { wrapCount++; cur = ""; } + const chars = [...wds[wi]]; + let piece = ""; + for (const ch of chars) { + const test = piece + ch; + if (piece && measureBidiLineWidth(doc, test, probeWrapOpts) > cellW) { + wrapCount++; + piece = ch; + } else { + piece = test; + } + } + if (piece) { wrapCount++; } + continue; + } + const test = cur ? cur + " " + wds[wi] : wds[wi]; + if (measureBidiLineWidth(doc, test, probeWrapOpts) > cellW) { + wrapCount++; + cur = wds[wi]; + } else { + cur = test; + } + } + if (cur) wrapCount++; + h += Math.max(1, wrapCount) * lineHeight; + } } const finalH = h + cellPadY * 2; cellHeights.push(finalH); diff --git a/artifacts/api-server/src/routes/executive-meetings.ts b/artifacts/api-server/src/routes/executive-meetings.ts index e65a6d63..1a588e89 100644 --- a/artifacts/api-server/src/routes/executive-meetings.ts +++ b/artifacts/api-server/src/routes/executive-meetings.ts @@ -2686,14 +2686,14 @@ router.get( startTime: m.startTime, endTime: m.endTime, location: m.location, - // Forward saved tint; isHighlighted is intentionally dropped. rowColor: m.rowColor, + mergeStartColumn: m.mergeStartColumn, + mergeEndColumn: m.mergeEndColumn, + mergeText: m.mergeText, attendees: (attendeesByMeeting.get(m.id) ?? []).map((a) => ({ name: a.name, title: a.title, attendanceType: a.attendanceType, - // Forward the row kind so the renderer can render subheadings - // as labels rather than numbered attendees. kind: a.kind, })), })), diff --git a/artifacts/tx-os/public/opengraph.jpg b/artifacts/tx-os/public/opengraph.jpg index 34569b426b342ca51ac6aae34b9fab28eaa7c4f2..173a27b515af14505853fa8ce6b0647ee49c330c 100644 GIT binary patch literal 25910 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 QI}a}k8gq2+bKl(kH&Kx^1ONa4 literal 25969 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 S+2`lW9Q27aW#pk>zW*1H=@PvF diff --git a/attached_assets/Pasted--PDF-PDF--1777885005658_1777885005659.txt b/attached_assets/Pasted--PDF-PDF--1777885005658_1777885005659.txt new file mode 100644 index 00000000..7b7afa1b --- /dev/null +++ b/attached_assets/Pasted--PDF-PDF--1777885005658_1777885005659.txt @@ -0,0 +1,151 @@ +أريد إصلاح تصدير PDF لجدول الاجتماعات بشكل نهائي. + +⚠️ مهم: +التصميم الخارجي للـPDF ثابت (العنوان + الفوتر + حجم الصفحة + الخط DIN Next LT Arabic). +التعديل فقط داخل الجدول. + +================================== +أولاً: إصلاح المشاكل الحالية +================================== + +1. لا يوجد أي فراغات بين الصفوف: +- لا padding عمودي +- لا margin +- ارتفاع الصف = حجم المحتوى فقط + +2. كل اجتماع يجب أن يكون صف واحد: +- الرقم + اسم الاجتماع + الحضور + الوقت في نفس الصف +- لا يظهر الوقت في صف منفصل أبداً + +3. إصلاح الترقيم: +- لا يبدأ من 4 أو رقم خاطئ +- استخدم رقم الاجتماع الحقيقي من البيانات + +4. إصلاح ترتيب الحضور: +- لا يظهر بشكل مقلوب مثل: + -5 سالم -4 علي +- الترتيب يكون: + 1- محمد 2- علي 3- طارق + +5. الدمج: +- أي merge في النظام (rowSpan / colSpan) يجب أن يظهر نفسه في PDF +- لا تعيد بناء الجدول بدون الدمج + +================================== +ثانياً: تنسيق الحضور +================================== + +- الحضور في نفس السطر (inline) +- كل سطر يحتوي 3 إلى 4 أسماء تقريباً +- إذا زاد العدد → ينزل سطر جديد تلقائياً +- لا تجعل كل اسم في سطر مستقل + +مثال: +1- محمد 2- علي 3- طارق +4- سالم 5- عبدالله + +================================== +ثالثاً: محاذاة المحتوى +================================== + +- عمود "الاجتماع" في المنتصف (center) +- عمود "الحضور" في المنتصف +- عمود "الوقت" في المنتصف +- vertical-align: middle + +================================== +رابعاً: عكس تنسيق المستخدم (مهم جداً) +================================== + +داخل الجدول فقط: + +- Bold → يظهر Bold في PDF +- Center / Right / Left → يظهر نفس المحاذاة +- لون الخط → يظهر نفسه +- لون الخلفية → يظهر نفسه +- حجم الخط → يظهر نفسه + +⚠️ لا تجعل CSS العام يلغي تنسيقات الخلايا + +الحل: +- استخدم inline style لكل خلية +- مثال: + + + المحتوى + + +================================== +خامساً: CSS المطلوب +================================== + +@media print { + table { + width: 100%; + border-collapse: collapse; + table-layout: fixed; + border-spacing: 0; + } + + th, td { + padding: 0 4px !important; + margin: 0 !important; + line-height: 1.05 !important; + vertical-align: middle !important; + text-align: center; + } + + .attendees-inline { + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + gap: 0 10px; + direction: rtl; + } + + .attendee-item { + white-space: nowrap; + unicode-bidi: isolate; + } + + .time-cell { + direction: ltr; + white-space: nowrap; + text-align: center; + } +} + +================================== +سادساً: شرط مهم جداً +================================== + +لا تبنِ PDF من DOM مكسور. + +- استخدم نفس بيانات الجدول في النظام +- طبّق rowSpan و colSpan كما هي +- كل صف في PDF = صف حقيقي في النظام + +================================== +النتيجة المطلوبة: +================================== + +PDF مطابق للنظام من حيث: +- بدون فراغات +- الحضور inline +- الترقيم صحيح +- الدمج صحيح +- الوقت داخل الصف +- المحاذاة في المنتصف +- جميع التنسيقات (Bold / Color / Alignment) تنعكس \ No newline at end of file