dbXapp 2.0
RAD, CMS, Module und Runtime-IDE fuer dbXapp
Loading...
Searching...
No Matches
print.js
Go to the documentation of this file.
1(function (window, document) {
2 "use strict";
3
4 if (!window.dbx) window.dbx = {};
5
6 /* =========================================================
7 CORE PRINT FUNCTION
8 ========================================================= */
9
10 dbx.print = function (configString) {
11
12 if (dbx._printing === true) {
13 dbx.log("warn", "[dbx.print] already printing");
14 return;
15 }
16
17 if (!configString || typeof configString !== "string") {
18 dbx.log("warn", "[dbx.print] Missing selector");
19 return;
20 }
21
22 const parsed = parseConfig(configString);
23
24 const original = document.querySelector(parsed.selector);
25 if (!original) {
26 dbx.log("warn", "[dbx.print] Selector not found:", parsed.selector);
27 return;
28 }
29
30 dbx._printing = true;
31
32 const clone = original.cloneNode(true);
33 clone.querySelectorAll(".noPrint").forEach(el => el.remove());
34
35 removeIfExists("dbx-print-root");
36 removeIfExists("dbx-print-style");
37
38 const root = document.createElement("div");
39 root.id = "dbx-print-root";
40
41 root.style.fontFamily = parsed.font;
42 root.style.fontSize = parsed.fontsize;
43 root.style.lineHeight = parsed.lineheight;
44
45 root.appendChild(clone);
46 document.body.appendChild(root);
47
48 document.body.classList.add("dbx-printing");
49
50 applyTableCompaction(root, parsed);
51
52 /* 🔥 APPLY DYNAMIC PAGE PADDING (PRINT) */
53 const pages = root.querySelectorAll(".print-page");
54
55 pages.forEach((page, index) => {
56
57 const parts = parsed.margin.split(" ");
58
59 let pt = parts[0] || "0";
60 let pr = parts[1] || parts[0] || "0";
61 let pb = parts[2] || parts[0] || "0";
62 let pl = parts[3] || parts[1] || parts[0] || "0";
63
64 if (index === 0) {
65 pt = "0mm";
66 }
67
68 page.style.paddingTop = pt;
69 page.style.paddingRight = pr;
70 page.style.paddingBottom = pb;
71 page.style.paddingLeft = pl;
72 });
73
74 const style = document.createElement("style");
75 style.id = "dbx-print-style";
76 style.media = "print";
77
78 style.innerHTML = `
79 @page {
80 size: ${parsed.format} ${parsed.orientation};
81 margin: 0;
82 }
83 `;
84
85 document.head.appendChild(style);
86
87 setTimeout(() => window.print(), 60);
88
89 const cleanup = function () {
90
91 document.body.classList.remove("dbx-printing");
92
93 removeIfExists("dbx-print-root");
94 removeIfExists("dbx-print-style");
95
96 dbx._printing = false;
97
98 window.removeEventListener("afterprint", cleanup);
99 };
100
101 window.addEventListener("afterprint", cleanup);
102 };
103
104
105 /* =========================================================
106 SCREEN MODE
107 ========================================================= */
108
109 function applyScreenMode(parsed) {
110
111 const target = document.querySelector(parsed.selector);
112 if (!target) return;
113
114 target.classList.add("dbx-screen-preview");
115
116 target.style.fontFamily = parsed.font;
117 target.style.fontSize = parsed.fontsize;
118 target.style.lineHeight = parsed.lineheight;
119
120 applyTableCompaction(target, parsed);
121
122 target.querySelectorAll(".print-page").forEach(page => {
123
124 const parts = parsed.margin.split(" ");
125
126 page.style.paddingTop = parts[0] || "0";
127 page.style.paddingRight = parts[1] || parts[0] || "0";
128 page.style.paddingBottom = parts[2] || parts[0] || "0";
129 page.style.paddingLeft = parts[3] || parts[1] || parts[0] || "0";
130
131 page.classList.remove("a4","a5","portrait","landscape");
132
133 page.classList.add(parsed.format.toLowerCase());
134 page.classList.add(parsed.orientation.toLowerCase());
135 });
136 }
137
138
139 /* =========================================================
140 TABLE COMPACTION ENGINE
141 ========================================================= */
142
143 function applyTableCompaction(container, parsed) {
144
145 let fontSizePx = parseFloat(parsed.fontsize) || 10;
146
147 let padding = parsed.padding;
148 let rowheight = parsed.rowheight;
149 let lineheight = parsed.lineheight;
150
151 if (padding !== null) {
152 if (!String(padding).includes("px")) {
153 padding = padding + "px";
154 }
155 }
156
157 if (rowheight !== null && rowheight !== "auto") {
158 if (!String(rowheight).includes("px")) {
159 rowheight = rowheight + "px";
160 }
161 }
162
163 if (parsed.compact === true) {
164
165 padding = Math.max(0, Math.floor(fontSizePx * 0.15)) + "px";
166 lineheight = "1.0";
167 rowheight = Math.floor(fontSizePx * 1.2) + "px";
168 }
169
170 if (rowheight === "auto") {
171
172 let lh = parseFloat(lineheight) || 1.2;
173 let pad = parseFloat(padding) || 0;
174
175 let calc = Math.ceil(fontSizePx * lh + (pad * 2));
176
177 rowheight = calc + "px";
178 }
179
180 if (rowheight) {
181 container.querySelectorAll("tr").forEach(tr => {
182 tr.style.height = rowheight;
183 });
184 }
185
186 container.querySelectorAll("td, th").forEach(cell => {
187
188 if (padding !== null) {
189 cell.style.padding = padding;
190 }
191
192 if (lineheight) {
193 cell.style.lineHeight = lineheight;
194 }
195 });
196 }
197
198
199 /* =========================================================
200 CONFIG PARSER
201 ========================================================= */
202
203 function parseConfig(configString) {
204
205 const parts = configString.split("|").map(p => p.trim());
206 const selector = parts[0];
207
208 const options = {
209 format: "A4",
210 orientation: "portrait",
211 margin: "12mm",
212 margin_top: null,
213 margin_right: null,
214 margin_bottom: null,
215 margin_left: null,
216 font: "Arial",
217 fontsize: "10px",
218 lineheight: "1.3",
219 rowheight: null,
220 padding: null,
221 compact: false,
222 screen: false
223 };
224
225 for (let i = 1; i < parts.length; i++) {
226
227 const [key, value] = parts[i].split("=").map(p => p.trim());
228 if (!key) continue;
229
230 switch (key.toLowerCase()) {
231
232 case "format":
233 options.format = value.toUpperCase();
234 break;
235
236 case "orientation":
237 options.orientation = value.toLowerCase();
238 break;
239
240 case "margin":
241 options.margin = value || "10mm";
242 break;
243
244 case "margin_top":
245 options.margin_top = value;
246 break;
247
248 case "margin_right":
249 options.margin_right = value;
250 break;
251
252 case "margin_bottom":
253 options.margin_bottom = value;
254 break;
255
256 case "margin_left":
257 options.margin_left = value;
258 break;
259
260 case "font":
261 options.font = (value || "").toLowerCase() === "ariel" ? "Arial" : value;
262 break;
263
264 case "fontsize":
265 options.fontsize = value;
266 break;
267
268 case "lineheight":
269 options.lineheight = value;
270 break;
271
272 case "rowheight":
273 options.rowheight = value;
274 break;
275
276 case "padding":
277 options.padding = value;
278 break;
279
280 case "compact":
281 options.compact = value === "1" || value === "true";
282 break;
283
284 case "screen":
285 options.screen = value === "1" || value === "true";
286 break;
287 }
288 }
289
290 let marginFinal = options.margin;
291
292 if (
293 options.margin_top !== null ||
294 options.margin_right !== null ||
295 options.margin_bottom !== null ||
296 options.margin_left !== null
297 ) {
298 const mt = options.margin_top || options.margin || "10mm";
299 const mr = options.margin_right || options.margin || "10mm";
300 const mb = options.margin_bottom || options.margin || "10mm";
301 const ml = options.margin_left || options.margin || "10mm";
302
303 marginFinal = `${mt} ${mr} ${mb} ${ml}`;
304 }
305
306 return {
307 selector,
308 format: options.format,
309 orientation: options.orientation,
310 margin: marginFinal,
311 font: options.font,
312 fontsize: options.fontsize,
313 lineheight: options.lineheight,
314 rowheight: options.rowheight,
315 padding: options.padding,
316 compact: options.compact,
317 screen: options.screen
318 };
319 }
320
321 function removeIfExists(id) {
322 const el = document.getElementById(id);
323 if (el) el.remove();
324 }
325
326
327 /* =========================================================
328 DBX FEATURE WRAPPER
329 ========================================================= */
330
331 if (window.dbx && dbx.feature) {
332
333 dbx.feature.register("print", {
334
335 scope: "element", // 🔥 FIX
336
337 // 🔥 CSS über PREPARE
338 css: [
339 ['css', 'design', 'c-print.css']
340 ],
341
342 priority: "mid",
343
344 init(el, config) {
345
346 if (!el) return;
347
348 // 🔥 INIT GUARD
349 el.__dbxInitialized = el.__dbxInitialized || {};
350 if (el.__dbxInitialized["print"]) return;
351 el.__dbxInitialized["print"] = true;
352
353 let target = config.target || config.selector;
354
355 if (!target) {
356 const container = el.closest("[id]");
357 if (container) {
358 target = "#" + container.id;
359 }
360 }
361
362 if (!target) {
363 dbx.warn("[dbx.print] No target defined.");
364 return;
365 }
366
367 let configString = target;
368
369 Object.keys(config).forEach(function (key) {
370
371 if (key === "target" || key === "selector" || key === "id")
372 return;
373
374 configString += "|" + key + "=" + config[key];
375 });
376
377 const parsed = parseConfig(configString);
378
379 if (parsed.screen === true) {
380 applyScreenMode(parsed);
381 }
382
383 el.addEventListener("click", function (e) {
384 e.preventDefault();
385 dbx.print(configString);
386 });
387 }
388 });
389 }
390
391})(window, document);