1function convertToDataURLviaCanvas(url, outputFormat, max_size = 100) { 2 return new Promise(function (resolve, rejected) { 3 var imageObj1 = new Image(); 4 imageObj1.src = url; 5 imageObj1.onload = function () { 6 var c = document.createElement("canvas"); 7 c.width = max_size; 8 c.height = max_size; 9 let width = 0; 10 let height = 0; 11 if (imageObj1.height > imageObj1.width) { 12 height = max_size; 13 width = (imageObj1.width / (imageObj1.height / height)); 14 } else { 15 width = max_size; 16 height = (imageObj1.height / (imageObj1.width / width)); 17 } 18 var ctx = c.getContext("2d"); 19 ctx.drawImage(imageObj1, ((max_size - width) / 2), ((max_size - height) / 2), width, height); 20 const dataUrl = c.toDataURL(); 21 resolve(dataUrl); 22 }; 23 imageObj1.onerror = async function (e) { 24 resolve(await convertToDataURLviaCanvas("resources/images/default_logo.svg", "data:image/svg+xml")); 25 }; 26 }); 27} 28 29function svgFileToString(iconpath) { 30 return new Promise(function (resolve, rejected) { 31 fetch(iconpath).then(response => response.text()).then(text => { 32 resolve(text); 33 }); 34 }); 35} 36 37function getColor(name, type = 'hex') { 38 let colorString = getComputedStyle(document.documentElement).getPropertyValue(name).toString().trim(); 39 if (!colorString) { 40 colorString = '#ffffff'; 41 } 42 let color = tinycolor(colorString); 43 if (type == 'hex') { 44 return color.toHexString(); 45 } 46 if (type == 'rgb') { 47 return color.toRgbString(); 48 } 49 if (type == 'rgb-array') { 50 return Object.values(color.toRgb()).slice(0, 3); 51 } 52 return 'rgb(255,255,255)'; 53} 54// Bilder fuer den PDF-Export: einmal pro Export laden und klein halten (spart RAM und Dateigroesse) 55const pdfTableImageMaxPx = 96; 56const pdfImageCache = new Map(); 57function clearPdfImageCache() { 58 pdfImageCache.clear(); 59} 60function cachedPdfImage(key, factory) { 61 if (!pdfImageCache.has(key)) { 62 pdfImageCache.set(key, factory()); 63 } 64 return pdfImageCache.get(key); 65} 66function getImageDimensions(file) { 67 return cachedPdfImage('dim|' + file, function () { 68 return new Promise(function (resolve, rejected) { 69 var i = new Image() 70 i.onload = function () { 71 const scale = Math.min(1, pdfTableImageMaxPx / Math.max(i.width, i.height)); 72 const canvas = document.createElement('canvas'); 73 const ctx = canvas.getContext('2d'); 74 canvas.width = Math.max(1, Math.round(i.width * scale)); 75 canvas.height = Math.max(1, Math.round(i.height * scale)); 76 ctx.drawImage(i, 0, 0, canvas.width, canvas.height); 77 const dataUrl = canvas.toDataURL(); 78 resolve({ w: canvas.width, h: canvas.height, data: dataUrl }) 79 }; 80 i.onerror = async function () { 81 // kaputter/fehlender Bildlink: Standardbild statt endlosem Warten 82 resolve({ w: 100, h: 100, data: await convertToDataURLviaCanvas("resources/images/default_logo.svg", "data:image/svg+xml") }); 83 }; 84 i.src = file 85 }); 86 }); 87} 88 89// Grosse Fotos vor dem Einbetten verkleinern. Gibt null zurueck, wenn das Original bleiben kann. 90function downscaleImageToDataUrl(url, maxPx = 1200, quality = 0.85) { 91 return new Promise(function (resolve) { 92 var i = new Image(); 93 i.onload = function () { 94 if (Math.max(i.width, i.height) <= maxPx) { 95 resolve(null); 96 return; 97 } 98 const scale = maxPx / Math.max(i.width, i.height); 99 const canvas = document.createElement('canvas'); 100 canvas.width = Math.round(i.width * scale); 101 canvas.height = Math.round(i.height * scale); 102 const ctx = canvas.getContext('2d'); 103 ctx.fillStyle = '#ffffff'; 104 ctx.fillRect(0, 0, canvas.width, canvas.height); 105 ctx.drawImage(i, 0, 0, canvas.width, canvas.height); 106 resolve(canvas.toDataURL('image/jpeg', quality)); 107 }; 108 i.onerror = function () { 109 resolve(null); 110 }; 111 i.src = url; 112 }); 113} 114 115function mergeImages(image1, image2) { 116 return new Promise(function (resolve, rejected) { 117 var imageObj1 = new Image(); 118 var imageObj2 = new Image(); 119 imageObj1.src = image1; 120 imageObj1.onerror = function () { 121 resolve(image1); 122 }; 123 imageObj1.onload = function () { 124 imageObj2.src = image2; 125 imageObj2.onerror = function () { 126 resolve(image1); 127 }; 128 imageObj2.onload = function () { 129 var c = document.createElement("canvas"); 130 c.width = 100; 131 c.height = 100; 132 let width = 0; 133 let height = 0; 134 if (imageObj1.height > imageObj1.width) { 135 height = 100; 136 width = (imageObj1.width / (imageObj1.height / height)); 137 } else { 138 width = 100; 139 height = (imageObj1.height / (imageObj1.width / width)); 140 } 141 var ctx = c.getContext("2d"); 142 ctx.drawImage(imageObj1, ((100 - width) / 2), ((100 - height) / 2), width, height); 143 ctx.drawImage(imageObj2, 60, 60, 40, 40); 144 const dataUrl = c.toDataURL(); 145 resolve(dataUrl); 146 } 147 }; 148 }); 149} 150 151const pdfMakerPTsPerMM = 2.83465; 152const pdfMakerPrefix = location.protocol + '//' + location.host + $('base').attr('href'); 153const pdfMakerPageSize = { a4: { l: { h: 210 * pdfMakerPTsPerMM, w: 297 * pdfMakerPTsPerMM }, p: { w: 210 * pdfMakerPTsPerMM, h: 297 * pdfMakerPTsPerMM } }, a3: { l: { h: 297 * pdfMakerPTsPerMM, w: 410 * pdfMakerPTsPerMM }, p: { w: 297 * pdfMakerPTsPerMM, h: 410 * pdfMakerPTsPerMM } } }; 154let pdfMakerSettings = { 155 border: 15 * pdfMakerPTsPerMM, 156 logoAPPECHeight: 7 * pdfMakerPTsPerMM, 157 logoAPPECWidth: 25 * pdfMakerPTsPerMM, 158 borderRightDiffA3: 5 * pdfMakerPTsPerMM, 159 borderRightDiffA4: 15 * pdfMakerPTsPerMM 160}; 161// init Fonts 162pdfMake.fonts = { 163 montserrat: { 164 normal: pdfMakerPrefix + 'files/webfonts/montserrat/Montserrat-Regular.ttf', 165 bold: pdfMakerPrefix + 'files/webfonts/montserrat/Montserrat-Bold.ttf', 166 italics: pdfMakerPrefix + 'files/webfonts/montserrat/Montserrat-Italic.ttf', 167 bolditalics: pdfMakerPrefix + 'files/webfonts/montserrat/Montserrat-BoldItalic.ttf' 168 } 169}; 170// options: continuation (Folgeteil einer Tabelle: ohne Titel/Logos), onProgress(zeile, gesamt), quiet (Ladeanzeige nicht anfassen), asBytes (Uint8Array statt Data-URL) 171function tableListToPDFMaker(data, accountLogo = null, title = '', ref_date = '', show_ref_date = true, options = {}) { 172 return new Promise(async function (resolve, reject) { 173 174 // init Fixed IMAGES 175 let myImages = {}; 176 myImages.logo = { 177 url: pdfMakerPrefix + 'resources/images/logo-pdf.png' 178 }; 179 if (accountLogo) { 180 myImages.accountLogo = { 181 url: pdfMakerPrefix + accountLogo 182 }; 183 } 184 185 let idxHiddenType = data[0].findIndex(x => x.name == 'hidden_type'); 186 let hiddenTypes = []; 187 if (idxHiddenType >= 0) { 188 for (let i = 0; i < data.length; i++) { 189 hiddenTypes.push(data[i].splice(idxHiddenType, 1)); 190 } 191 } 192 193 let idxSoonToOld = data[0].findIndex(x => x.name == 'soon_to_old'); 194 let soonToOld = []; 195 if (idxSoonToOld >= 0) { 196 for (let i = 0; i < data.length; i++) { 197 soonToOld.push(data[i].splice(idxSoonToOld, 1)); 198 } 199 } 200 201 let idxDarwDirLine = data[0].findIndex(x => x.name == 'add_row_line'); 202 let drawRowLine = []; 203 if (idxDarwDirLine >= 0) { 204 for (let i = 0; i < data.length; i++) { 205 drawRowLine.push(data[i].splice(idxDarwDirLine, 1)); 206 } 207 } 208 let idxDirName = data[0].findIndex(x => x.col_name == 'dir_names'); 209 // Manipulate-Data 210 // Column Length of Table 211 let columnCount = 0; 212 let dataForTableBody = []; 213 let myWidths = []; 214 215 for (let i = 0; i < data.length; i++) { 216 columnCount = data[i].length; 217 } 218 219 // Head-Row Color 220 dataForTableBody.push(data[0].map((x) => { 221 myWidths.push(x.width); 222 return { text: x.name, color: getColor('--color-primary-contrast'), bold: true }; 223 })); 224 if (!myWidths.includes('*')) { 225 if (myWidths.length > 2) { 226 myWidths[2] = '*'; 227 } else if (myWidths.length > 1) { 228 myWidths[1] = '*'; 229 } 230 } 231 if (language == 'bz') { 232 dataForTableBody.push(data[0].map((x) => { 233 return { text: otherTranslate['it'][x.const_name], color: getColor('--color-primary-contrast'), bold: true }; 234 })); 235 } 236 237 // Generate Body Rows 238 let tmpArr = data.slice(1); 239 for (let i = 0; i < tmpArr.length; i++) { 240 for (let j = 0; j < tmpArr[i].length; j++) { 241 let col = {}; 242 if (tmpArr[i][j] == null || tmpArr[i][j] == '') { 243 col['text'] = '/'; 244 } else { 245 // Change br to nl 246 tmpArr[i][j] = tmpArr[i][j].toString().replace('<br />', "\n"); 247 // Add Not Ok String 248 if (tmpArr[i][j].startsWith('EXPORT_DATE_NOT_OK ')) { 249 col = { 250 text: tmpArr[i][j].replace('EXPORT_DATE_NOT_OK ', (translate['TEST']['DATE_NOT_OK'] + (language == 'bz' ? "/" + otherTranslate['it']['TEST']['DATE_NOT_OK'] : '') + "\n")), 251 bold: true 252 } 253 // Change Image-Url to Table Image 254 } else if (tmpArr[i][j].match(/\.(jpeg|jpg|png|svg)$/) != null) { 255 const imageUrl = tmpArr[i][j]; 256 const isDir = (idxHiddenType >= 0 && hiddenTypes[i + 1] == 'dir'); 257 const isSoonToOld = (idxSoonToOld >= 0 && soonToOld[i + 1] == '1'); 258 // gleiche Bilder (z. B. gleiches Modell) nur einmal laden und verkleinern 259 let tmpImageData = await cachedPdfImage('row|' + imageUrl + '|' + isDir + '|' + isSoonToOld, async function () { 260 let imageData = null; 261 if (imageUrl.match(/\.(svg)$/) != null) { 262 imageData = await convertToDataURLviaCanvas(imageUrl, "data:image/svg+xml"); 263 } else { 264 imageData = (await getImageDimensions(imageUrl)).data; 265 } 266 if (isDir) { 267 imageData = await mergeImages(imageData, pdfMakerPrefix + 'resources/images/default_dir.svg'); 268 } 269 if (isSoonToOld) { 270 imageData = await mergeImages(imageData, pdfMakerPrefix + 'resources/images/soon_to_old.svg'); 271 } 272 return imageData; 273 }); 274 if (options.onProgress) { 275 options.onProgress(i + 1, tmpArr.length); 276 } else { 277 showLoading(translate['TEST']['FILE_WILL_BE_EXPORTED'] + '<br />' + translate['TEST']["FILE_WILL_BE_EXPORTED_STEP_5"].replace('##', (i + 2)).replace('%%', tmpArr.length)); 278 } 279 col = { 280 image: tmpImageData, 281 fit: [40, 40],
282 metaBackgroundCell: null 283 } 284 } else if (tmpArr[i][j].startsWith('STATE_')) { 285 let stateColor = '--color-font-default'; 286 switch (tmpArr[i][j]) { 287 case 'STATE_1_TO_OLD': 288 stateColor = '--color-to-old'; 289 break; 290 case 'STATE_2_OVERDUE': 291 case 'STATE_TEST_3_NOT_OK': 292 stateColor = '--color-danger'; 293 break; 294 case 'STATE_3_UPCOMING': 295 stateColor = '--color-warning'; 296 break; 297 case 'STATE_4_INSPECTED': 298 case 'STATE_TEST_1_OK': 299 stateColor = '--color-success'; 300 break; 301 case 'STATE_5_IN_REPAIR': 302 case 'STATE_TEST_2_IN_REPAIR': 303 stateColor = '--color-in-repair'; 304 break; 305 case 'STATE_6_IN_STOCK': 306 stateColor = '--color-default-medium'; 307 break; 308 case 'STATE_7_NOT_BE_CHECKED': 309 stateColor = '--color-light-default'; 310 break; 311 case 'STATE_8_NOT_FOUND': 312 stateColor = '--color-not-found'; 313 break; 314 case 'STATE_9_DISCARDED': 315 stateColor = '--color-not-ok'; 316 break; 317 case 'STATE_10_EMPTY': 318 stateColor = '--color-font-default'; 319 break; 320 } 321 col = { text: getStateTranslate(tmpArr[i][j]), metaBackgroundCell: getColor(stateColor), color: getColor(stateColor + '-contrast'), bold: true/*, fillOpacity: 0.5*/ } 322 } else { 323 col['text'] = tmpArr[i][j]; 324 } 325 } 326 tmpArr[i][j] = col; 327 } 328 if (idxDarwDirLine >= 0) { 329 if (drawRowLine[i + 1] == 'ADD_ROW_LINE') { 330 dataForTableBody.push([{ 331 colSpan: columnCount, 332 text: tmpArr[i][idxDirName], 333 border: [false, true, false, true], 334 alignment: 'center', 335 bold: true, 336 style: 'fontSizeNormal', 337 margin: [0, 5, 0, 5] 338 }]); 339 } 340 } 341 dataForTableBody.push(tmpArr[i]); 342 } 343 if (!options.quiet) { 344 await hideLoading(true); 345 await showLoading(translate['TEST']['FILE_WILL_BE_EXPORTED_STEP_6']); 346 } 347 348 // Generate Content 349 let myContent = []; 350 351 // Title 352 if (!options.continuation) { 353 myContent.push({ 354 text: title, 355 style: 'fontSizeHeading2' 356 }); 357 } 358 359 // Ref-Date 360 if (ref_date !== '' && show_ref_date && !options.continuation) { 361 myContent.push({ 362 text: (translate['ARTICLE']['REF_DATE'] + (language == 'bz' ? ' - ' + otherTranslate['it']['ARTICLE']['REF_DATE'] : '') + ': ' + ref_date), 363 style: 'fontSizeNormal', 364 absolutePosition: { x: pdfMakerSettings.border, y: 11 * pdfMakerPTsPerMM } 365 }); 366 } 367 368 // Logo 369 if (!options.continuation) { 370 myContent.push({ 371 image: 'logo', 372 width: pdfMakerSettings.logoAPPECWidth, 373 height: pdfMakerSettings.logoAPPECHeight, 374 absolutePosition: { x: (((columnCount > 9) ? (pdfMakerPageSize.a3.l.w - pdfMakerSettings.borderRightDiffA3) : (pdfMakerPageSize.a4.l.w - pdfMakerSettings.borderRightDiffA4)) - pdfMakerSettings.logoAPPECWidth), y: pdfMakerSettings.border } 375 }); 376 } 377 378 // Account-Logo 379 if (accountLogo && !options.continuation) { 380 myContent.push({ 381 image: 'accountLogo', 382 fit: [pdfMakerSettings.logoAPPECWidth, pdfMakerSettings.logoAPPECHeight], 383 absolutePosition: { x: (((columnCount > 9) ? (pdfMakerPageSize.a3.l.w - pdfMakerSettings.borderRightDiffA3) : (pdfMakerPageSize.a4.l.w - pdfMakerSettings.borderRightDiffA4)) - 10 - (pdfMakerSettings.logoAPPECWidth * 2)), y: pdfMakerSettings.border } 384 }); 385 } 386 // Table 387 myContent.push({ 388 style: ((columnCount > 15) ? 'fontSizeMini' : 'fontSizeSmall'), 389 absolutePosition: { x: pdfMakerSettings.border, y: pdfMakerSettings.border + (options.continuation ? 0 : (10 * pdfMakerPTsPerMM)) }, 390 alignment: 'left', 391 table: { 392 widths: myWidths, 393 body: dataForTableBody, 394 dontBreakRows: true 395 }, 396 layout: { 397 defaultBorder: false, 398 fillColor: function (rowIndex, node, columnIndex) { 399 if (dataForTableBody[rowIndex][columnIndex]["metaBackgroun
399dCell"] !== undefined) { 400 return dataForTableBody[rowIndex][columnIndex]["metaBackgroundCell"]; 401 } 402 if (rowIndex == 0 || (rowIndex == 1 && language == 'bz')) { 403 return getColor('--color-primary'); 404 } else if (rowIndex % 2 === 0) { 405 return getColor('--color-light-default'); 406 } 407 return null; 408 } 409 } 410 }); 411 412 // Generate PDF 413 var docDefinition = { 414 pageSize: ((columnCount > 9) ? 'A3' : 'A4'), 415 pageOrientation: 'landscape', 416 compress: true, 417 pageBreakBefore: false, 418 pageMargins: [pdfMakerSettings.border, pdfMakerSettings.border, pdfMakerSettings.border, pdfMakerSettings.border], 419 defaultStyle: { 420 font: 'montserrat' 421 }, 422 images: myImages, 423 styles: { 424 fontSizeMini: { 425 fontSize: 6, 426 lineHeight: 1 427 }, 428 fontSizeSmall: { 429 fontSize: 7, 430 lineHeight: 1 431 }, 432 fontSizeNormal: { 433 fontSize: 9, 434 lineHeight: 1 435 }, 436 fontSizeBig: { 437 fontSize: 11, 438 lineHeight: 1 439 }, 440 fontSizeHeading2: { 441 fontSize: 16, 442 lineHeight: 1 443 }, 444 anotherStyle: { 445 italics: true, 446 alignment: 'right' 447 } 448 }, 449 content: myContent 450 }; 451 const pdfDocGenerator = pdfMake.createPdf(docDefinition); 452 if (options.asBytes) { 453 pdfDocGenerator.getBuffer((buffer) => { 454 resolve(buffer); 455 }); 456 } else { 457 pdfDocGenerator.getDataUrl((dataUrl) => { 458 resolve(dataUrl); 459 }); 460 } 461 }); 462} 463// options: asBytes (Uint8Array statt Base64-Data-URL) 464function testToPDF(data, accountLogo = null, with_attachments = false, options = {}) { 465 return new Promise(async function (resolve, reject) { 466 467 // init Fixed IMAGES 468 let myImages = {}; 469 myImages.logo = { 470 url: pdfMakerPrefix + 'resources/images/logo-pdf.png' 471 }; 472 myImages.questionIcons3 = { 473 url: pdfMakerPrefix + 'resources/images/question-icon-3.png' 474 }; 475 myImages.questionIcons2 = { 476 url: pdfMakerPrefix + 'resources/images/question-icon-2.png' 477 }; 478 myImages.questionIcons1 = { 479 url: pdfMakerPrefix + 'resources/images/question-icon-1.png' 480 }; 481 myImages.questionIcons0 = { 482 url: pdfMakerPrefix + 'resources/images/question-icon-0.png' 483 }; 484 if (accountLogo) { 485 myImages.accountLogo = { 486 url: pdfMakerPrefix + accountLogo 487 }; 488 } 489 if (data['sign']) { 490 myImages.sign = { 491 url: pdfMakerPrefix + data['sign'] 492 }; 493 } 494 495 // Generate Content 496 let myContent = []; 497 498 // Title 499 myContent.push({ 500 text: translate['TEST']['EXPORT_TEST_TITLE'] + (language == 'bz' ? " - " + otherTranslate['it']['TEST']['EXPORT_TEST_TITLE'] : ''), 501 style: 'fontSizeHeading2' 502 }); 503 504 // Logo 505 myContent.push({ 506 image: 'logo', 507 width: pdfMakerSettings.logoAPPECWidth, 508 height: pdfMakerSettings.logoAPPECHeight, 509 absolutePosition: { x: ((pdfMakerPageSize.a4.p.w - pdfMakerSettings.borderRightDiffA4) - pdfMakerSettings.logoAPPECWidth), y: pdfMakerSettings.border } 510 }); 511 512 // Account-Logo 513 if (accountLogo) { 514 myContent.push({ 515 image: 'accountLogo', 516 fit: [pdfMakerSettings.logoAPPECWidth, pdfMakerSettings.logoAPPECHeight], 517 absolutePosition: { x: ((pdfMakerPageSize.a4.p.w - pdfMakerSettings.borderRightDiffA4) - 10 - (pdfMakerSettings.logoAPPECWidth * 2)), y: pdfMakerSettings.border } 518 }); 519 } 520 myContent.push({ 521 canvas: [ 522 { 523 type: 'line', 524 x1: 0, y1: (3 * pdfMakerPTsPerMM), 525 x2: (pdfMakerPageSize.a4.p.w - (pdfMakerSettings.border * 2)), y2: (3 * pdfMakerPTsPerMM), 526 lineWidth: 1, 527 lineColor: getColor('--color-primary') 528 } 529 ] 530 }); 531 let tableData = [ 532 { col1: 'SERIAL_NUMBER', col2: 'article_serial_number' }, 533 { col1: 'PERSONAL_ID', col2: 'article_personal_id' }, 534 { col1: 'NFC_ID', col2: 'article_nfc_id' }, 535 { col1: 'MANUFACTURE', col2: 'article_manufacture_name' }, 536 { col1: 'MODEL', col2: 'article_model_name' }, 537 { col1: 'MODEL_NR', col2: 'article_model_nr' }, 538 { col1: 'MODEL_CATEGORY', col2: 'article_model_category_name' }, 539 { col1: 'DATE_OF_MANUFACTURE', col2: 'article_date_of_manufacture' }, 540 { col1: 'DATE_OF_PURCHASE', col2: 'article_date_of_purchase' }, 541 { col1: 'DATE_FIRST_USE', col2: 'article_date_first_use' }, 542 543 ]; 544 if (data['article_expire_date'] != '') { 545 tableData.push( 546 { col1: 'EXPIRE_DATE', col2: 'article_expire_date', color: (data['article_to_old'] ? getColor('--color-danger') : (data['article_soon_to_old'] ? getColor('--color-warning-shade') : getColor('--color-font-default'))) } 547 ); 548 } 549 tableData.push({ col1: 'DIR', col2: 'article_dir_names' }); 550 tableData.push({ col1: 'MODEL_STANDARTS', col2: 'article_model_standarts' }); 551 552 let myTableBody = []; 553 for (let i = 0; i < tableData.length; i++) { 554 myTableBody.push([ 555 { text: (translate['ARTICLE'][tableData[i].col1] + (language == 'bz' ? "\n" + otherTranslate['it']['ARTICLE'][tableData[i].col1] : '')), bold: true, margin: (language == 'bz' ? [0, 0, 0, 0] : [0, 2.5, 0, 2.5]), color: (tableData[i]['color'] ? tableData[i]['color'] : getColor('--color-font-default')) }, 556 { text: data[tableData[i].col2], margin: (language == 'bz' ? [0, 0, 0, 0] : [0, 2.5, 0, 2.5]), color: (tableData[i]['color'] ? tableData[i]['color'] : getColor('--color-font-default')), italics: true } 557 ]); 558 } 559 let myWidths = ['auto', '*']; 560 if (data['image']) { 561 myWidths = ['auto', '*', 'auto']; 562 // grosse Fotos verkleinern, sonst wird pro Pruefung das Original eingebettet 563 myImages.testImage = (await downscaleImageToDataUrl(pdfMakerPrefix + data['image'], 1200)) || { 564 url: pdfMakerPrefix + data['image'] 565 }; 566 myTableBody[0].push({ 567 image: 'testImage', 568 fit: [(85 * pdfMakerPTsPerMM), (85 * pdfMakerPTsPerMM)], 569 rowSpan: myTableBody.length 570 }) 571 } 572 573 574 // Table 575 myContent.push({ 576 margin: [0, 10, 0, 0], 577 style: (language == 'bz' ? 'fontSizeSmall' : 'fontSizeNormal'), 578 alignment: 'left', 579 table: { 580 widths: myWidths, 581 body: myTableBody 582 }, 583 layout: { 584 defaultBorder: false, 585 paddingLeft: function (i, node, colIdx) { 586 return 0; 587 }, 588 paddingRight: function (i, node, colIdx) { 589 if (i == 0) { 590 return 5; 591 } 592 return 0; 593 } 594 } 595 }); 596 597 // Table 598 myContent.push({ 599 margin: [0, 0, 0, 10], 600 style: (language == 'bz' ? 'fontSizeSmall' : 'fontSizeNormal'), 601 alignment: 'left', 602 table: { 603 widths: ['*'], 604 body: [ 605 [ 606 { text: (translate['ARTICLE']['COMMENT'] + (language == 'bz' ? " - " + otherTranslate['it']['ARTICLE']['COMMENT'] : '')), bold: true, margin: [0, 2.5, 0, 0] } 607 ], [
608 { text: data['article_comment'], margin: [0, 0, 0, 0], italics: true } 609 ] 610 ] 611 612 613 }, 614 layout: { 615 defaultBorder: false, 616 paddingLeft: function (i, node) { return 0; }, 617 paddingRight: function (i, node) { return 0; } 618 } 619 }); 620 621 // Table States 622 myContent.push({ 623 style: 'fontSizeNormal', 624 alignment: 'left', 625 table: { 626 widths: [(5 * pdfMakerPTsPerMM), "*", (5 * pdfMakerPTsPerMM), "*", (5 * pdfMakerPTsPerMM), "*", (5 * pdfMakerPTsPerMM), "*"], 627 body: [ 628 [ 629 { 630 image: 'questionIcons3', 631 fit: [(5 * pdfMakerPTsPerMM), (5 * pdfMakerPTsPerMM)], 632 margin: [0, 4, 0, 4] 633 }, 634 { 635 text: translate['TEST']['GOOD_CONDITION'] + (language == 'bz' ? "\n" + otherTranslate['it']['TEST']['GOOD_CONDITION'] : ''), 636 margin: (language == 'bz' ? [0, 0, 0, 0] : [0, 6, 0, 6]) 637 }, 638 { 639 image: 'questionIcons2', 640 fit: [(5 * pdfMakerPTsPerMM), (5 * pdfMakerPTsPerMM)], 641 margin: [0, 4, 0, 4] 642 }, 643 { 644 text: translate['TEST']['MONITOR_CONDITION'] + (language == 'bz' ? "\n" + otherTranslate['it']['TEST']['MONITOR_CONDITION'] : ''), 645 margin: (language == 'bz' ? [0, 0, 0, 0] : [0, 6, 0, 6]) 646 }, { 647 image: 'questionIcons1', 648 fit: [(5 * pdfMakerPTsPerMM), (5 * pdfMakerPTsPerMM)], 649 margin: [0, 4, 0, 4] 650 }, 651 { 652 text: translate['TEST']['BAD_CONDITION'] + (language == 'bz' ? "\n" + otherTranslate['it']['TEST']['BAD_CONDITION'] : ''), 653 margin: (language == 'bz' ? [0, 0, 0, 0] : [0, 6, 0, 6]) 654 }, { 655 image: 'questionIcons0', 656 fit: [(5 * pdfMakerPTsPerMM), (5 * pdfMakerPTsPerMM)], 657 margin: [0, 4, 0, 4] 658 }, 659 { 660 text: translate['TEST']['NOT_APPLICABLE'] + (language == 'bz' ? "\n" + otherTranslate['it']['TEST']['NOT_APPLICABLE'] : ''), 661 margin: (language == 'bz' ? [0, 0, 0, 0] : [0, 6, 0, 6]) 662 } 663 ] 664 ], 665 dontBreakRows: true 666 }, 667 layout: {
668 hLineWidth: function (i, node) { 669 return 1; 670 }, 671 hLineColor: function (i, node) { 672 return getColor('--color-default-medium'); 673 }, 674 vLineWidth: function (i, node) { 675 return 0; 676 }, 677 vLineColor: function (i, node) { 678 return null; 679 } 680 } 681 }); 682 const questionValueText = { 683 3: translate['TEST']['GOOD_CONDITION'] + (language == 'bz' ? "\n" + otherTranslate['it']['TEST']['GOOD_CONDITION'] : ''), 684 2: translate['TEST']['MONITOR_CONDITION'] + (language == 'bz' ? "\n" + otherTranslate['it']['TEST']['MONITOR_CONDITION'] : ''), 685 1: translate['TEST']['BAD_CONDITION'] + (language == 'bz' ? "\n" + otherTranslate['it']['TEST']['BAD_CONDITION'] : ''), 686 0: translate['TEST']['NOT_APPLICABLE'] + (language == 'bz' ? "\n" + otherTranslate['it']['TEST']['NOT_APPLICABLE'] : '') 687 }; 688 for (let i = 0; i < data['checklists'].length; i++) { 689 let myChecklistBody = []; 690 691 692 myChecklistBody.push([ 693 { 694 stack: 695 [ 696 { 697 table: { 698 body: [ 699 [ 700 { 701 svg: await svgFileToString(pdfMakerPrefix + 'resources/images/question-icon-check.svg'), 702 fit: [(5 * pdfMakerPTsPerMM), (5 * pdfMakerPTsPerMM)] 703 }, 704 { 705 text: data['checklists'][i]['name'], 706 style: 'fontSizeBig', 707 bold: true 708 } 709 ] 710 ], 711 dontBreakRows: true 712 }, 713 layout: { 714 defaultBorder: false, 715 margin: false, 716 paddingLeft: function (i, node) { return 0; }, 717 paddingRight: function (i, node) { return 5; }, 718 paddingTop: function (i, node) { return 0; }, 719 paddingBottom: function (i, node) { return 0; } 720 }, 721 } 722 ], 723 colSpan: 2, 724 border: [false, false, false, true], 725 padding: 0 726 }, 727 { 728 } 729 ]) 730 if (data['checklists'][i]['checklists_json'].length > 0) { 731 for (let j = 0; j < data['checklists'][i]['checklists_json'].length; j++) { 732 if (data['checklists'][i]['checklists_json'][j]['type'] == 'text') { 733 myChecklistBody.push([ 734 { 735 stack: 736 [ 737 { 738 text: data['checklists'][i]['checklists_json'][j]['text'], style: 'fontSizeSmall', margin: [0, 5, 0, 2], bold: true 739 }, { 740 text: data['checklists'][i]['checklists_json'][j]['value'], style: 'fontSizeSmall', margin: [0, 2, 0, 5], italics: true, 741 } 742 ], 743 colSpan: 2 744 } 745 ]); 746 } else { 747 myChecklistBody.push([ 748 { text: data['checklists'][i]['checklists_json'][j]['text'], style: 'fontSizeSmall', margin: [0, 5, 0, 5] }, 749 { 750 stack: 751 [ 752 { 753 image: 'questionIcons' + (data['checklists'][i]['checklists_json'][j]['value']), 754 fit: [(5 * pdfMakerPTsPerMM), (5 * pdfMakerPTsPerMM)], 755 alignment: 'center' 756 }, { 757 text: questionValueText[data['checklists'][i]['checklists_json'][j]['value']],
758 margin: [0, 2, 0, 0], 759 alignment: 'center' 760 } 761 ], 762 margin: [0, 5, 0, 5], 763 alignment: 'right' 764 } 765 ]); 766 } 767 768 } 769 } 770 else { 771 myChecklistBody.push([ 772 { 773 text: translate['TEST']['CHECKLIST_HAS_NO_QUESTIONS'] + (language == 'bz' ? "\n" + otherTranslate['it']['TEST']['CHECKLIST_HAS_NO_QUESTIONS'] : ''), 774 colSpan: 2, 775 border: [false, false, false, false], 776 style: 'fontSizeBig', 777 margin: [0, 5, 0, 5], 778 alignment: 'center' 779 } 780 ]) 781 } 782 // Checklists 783 myContent.push({ 784 style: 'fontSizeSmall', 785 alignment: 'left', 786 margin: [0, 10, 0, 10], 787 table: { 788 widths: ['*', 70], 789 body: myChecklistBody, 790 dontBreakRows: true 791 }, 792 layout: {
793 hLineWidth: function (i, node) { 794 return 1; 795 }, 796 hLineColor: function (i, node) { 797 if (i == 1) { 798 return getColor('--color-primary'); 799 } 800 return getColor('--color-default-medium'); 801 }, 802 vLineWidth: function (i, node) { 803 return 0; 804 }, 805 vLineColor: function (i, node) { 806 return null; 807 }, 808 paddingLeft: function (i, node) { return 0; }, 809 paddingRight: function (i, node) { return 0; } 810 } 811 }); 812 } 813 814 // comment Test 815 myContent.push({ 816 style: 'fontSizeNormal', 817 alignment: 'left', 818 margin: [0, 10, 0, 10], 819 table: { 820 widths: ['*'], 821 body: [ 822 [ 823 { 824 text: (translate['TEST']['COMMENT'] + (language == 'bz' ? " - " + otherTranslate['it']['TEST']['COMMENT'] : '')), bold: true, margin: [0, 4, 0, 0], border: [false, true, false, false] 825 } 826 ], 827 [ 828 { text: data['comment'], margin: [0, 0, 0, 4], italics: true, border: [false, false, false, true] } 829 ] 830 ], 831 dontBreakRows: true 832 }, 833 layout: {
834 hLineWidth: function (i, node) { 835 return 1; 836 }, 837 hLineColor: function (i, node) { 838 return getColor('--color-primary'); 839 }, 840 vLineWidth: function (i, node) { 841 return 0; 842 }, 843 vLineColor: function (i, node) { 844 return null; 845 }, 846 paddingLeft: function (i, node) { return 0; }, 847 paddingRight: function (i, node) { return 0; } 848 } 849 }); 850 851 if (data['article_not_ok'] == '1') { 852 myContent.push( 853 { text: translate['TEST']['EXPORT_STATE_TEST_3_NOT_OK'] + (language == 'bz' ? " - " + otherTranslate['it']['TEST']['EXPORT_STATE_TEST_3_NOT_OK'] : ''), margin: [0, 4, 0, 4], bold: true, style: "fontSizeBig", color: getColor('--color-danger'), alignment: 'center' } 854 ); 855 } else if (data['article_in_repair'] == '1') { 856 myContent.push( 857 { text: translate['TEST']['EXPORT_STATE_TEST_2_IN_REPAIR'] + (language == 'bz' ? " - " + otherTranslate['it']['TEST']['EXPORT_STATE_TEST_2_IN_REPAIR'] : ''), margin: [0, 4, 0, 4], bold: true, style: "fontSizeBig", color: getColor('--color-in-repair'), alignment: 'center' } 858 ); 859 } else { 860 myContent.push( 861 { text: translate['TEST']['EXPORT_STATE_TEST_1_OK'] + (language == 'bz' ? " - " + otherTranslate['it']['TEST']['EXPORT_STATE_TEST_1_OK'] : ''), margin: [0, 4, 0, 4], bold: true, style: "fontSizeBig", color: getColor('--color-success'), alignment: 'center' } 862 ); 863 } 864 865 myTableBody = []; 866 867 myTableBody.push([ 868 { 869 text: translate['TEST']['EXPORT_TESTED_BY'] + (language == 'bz' ? "\n" + otherTranslate['it']['TEST']['EXPORT_TESTED_BY'] : ''), 870 bold: true, 871 margin: [0, 0, 5, 0] 872 }, 873 { 874 text: data['tester_name'], 875 italics: true 876 }, 877 { 878 text: translate['TEST']['EXPORT_ACCOUNT_NAME'] + (language == 'bz' ? "\n" + otherTranslate['it']['TEST']['EXPORT_ACCOUNT_NAME'] : ''), 879 bold: true, 880 margin: [0, 0, 5, 0] 881 }, 882 { 883 text: data['account_name'], 884 italics: true 885 } 886 ]); 887 if (data['article_not_ok'] == '1') { 888 myTableBody.push([ 889 { 890 text: translate['TEST']['DATE'] + (language == 'bz' ? "\n" + otherTranslate['it']['TEST']['DATE'] : ''), 891 bold: true, 892 margin: [0, 0, 5, 0] 893 }, 894 { 895 text: data['date'], 896 italics: true 897 }, 898 { 899 text: translate['TEST']['DATE_NOT_OK'] + (language == 'bz' ? "\n" + otherTranslate['it']['TEST']['DATE_NOT_OK'] : ''), 900 bold: true, 901 color: getColor('--color-danger'), 902 margin: [0, 0, 5, 0] 903 }, 904 { 905 text: data['article_date_not_ok'], 906 italics: true, 907 color: getColor('--color-danger') 908 } 909 ]); 910 } else if (data['article_in_repair'] == '1') { 911 myTableBody.push([ 912 { 913 text: translate['TEST']['DATE'] + (language == 'bz' ? "\n" + otherTranslate['it']['TEST']['DATE'] : ''), 914 bold: true, 915 margin: [0, 0, 5, 0] 916 }, 917 { 918 text: data['date'], 919 italics: true 920 }, 921 { 922 text: "", 923 bold: true, 924 color: getColor('--color-danger'), 925 margin: [0, 0, 5, 0] 926 }, 927 { 928 text: "", 929 italics: true, 930 color: getColor('--color-danger') 931 } 932 ]); 933 } else { 934 935 myTableBody.push([ 936 { 937 text: translate['TEST']['DATE'] + (language == 'bz' ? "\n" + otherTranslate['it']['TEST']['DATE'] : ''), 938 bold: true, 939 margin: [0, 0, 5, 0] 940 }, 941 { 942 text: data['date'], 943 italics: true 944 }, 945 { 946 text: translate['TEST']['DATE_NEXT_TEST'] + (language == 'bz' ? "\n" + otherTranslate['it']['TEST']['DATE_NEXT_TEST'] : ''), 947 bold: true, 948 margin: [0, 0, 5, 0] 949 }, 950 { 951 text: data['date_next_control'], 952 italics: true 953 } 954 ]); 955 } 956 957 myContent.push({ 958 style: 'fontSizeNormal', 959 alignment: 'left', 960 margin: [0, 10, 0, 10], 961 table: { 962 widths: ['auto', '*', 'auto', '*'], 963 body: myTableBody, 964 dontBreakRows: true 965 }, 966 layout: {
967 hLineWidth: function (i, node) { 968 return 0; 969 }, 970 hLineColor: function (i, node) { 971 return null; 972 }, 973 vLineWidth: function (i, node) { 974 return 0; 975 }, 976 vLineColor: function (i, node) { 977 return null; 978 }, 979 paddingLeft: function (i, node) { return 0; }, 980 paddingRight: function (i, node) { return 0; } 981 } 982 }); 983 984 if (data['sign']) { 985 myContent.push({ 986 image: 'sign', 987 fit: [(38 * pdfMakerPTsPerMM), (19 * pdfMakerPTsPerMM)] 988 }); 989 } else { 990 myContent.push({ 991 text: (translate['TEST']['EXPORT_SIGN'] + (language == 'bz' ? "\n" + otherTranslate['it']['TEST']['EXPORT_SIGN'] : '')) 992 }); 993 } 994 995 // Generate PDF 996 var docDefinition = { 997 pageSize: 'A4', 998 pageOrientation: 'portrait', 999 compress: true, 1000 pageBreakBefore: false, 1001 pageMargins: [pdfMakerSettings.border, pdfMakerSettings.border, pdfMakerSettings.border, pdfMakerSettings.border], 1002 defaultStyle: { 1003 font: 'montserrat' 1004 }, 1005 images: myImages, 1006 styles: { 1007 fontSizeMini: { 1008 fontSize: 6, 1009 lineHeight: 1 1010 }, 1011 fontSizeSmall: { 1012 fontSize: 7, 1013 lineHeight: 1 1014 }, 1015 fontSizeNormal: { 1016 fontSize: 9, 1017 lineHeight: 1 1018 }, 1019 fontSizeBig: { 1020 fontSize: 11, 1021 lineHeight: 1 1022 }, 1023 fontSizeHeading2: { 1024 fontSize: 16, 1025 lineHeight: 1 1026 }, 1027 anotherStyle: { 1028 italics: true, 1029 alignment: 'right' 1030 } 1031 }, 1032 content: myContent 1033 }; 1034 const pdfDocGenerator = pdfMake.createPdf(docDefinition); 1035 1036 pdfDocGenerator.getBuffer(async (mainPdfBytes) => { 1037 if (!with_attachments) 1038 data['attachments'] = []; 1039 1040 let finalPdf = await mergePdfsAndImages([mainPdfBytes, ...data['attachments']], !!options.asBytes); 1041 1042 resolve(finalPdf); 1043 }); 1044 }); 1045} 1046async function generateTitlePagePDF(data = {}) { 1047 return new Promise(async function (resolve, reject) { 1048 1049 let myImages = {}; 1050 myImages.logo = { 1051 url: pdfMakerPrefix + 'resources/images/logo-pdf.png' 1052 }; 1053 if (data['logo']) { 1054 myImages.accountLogo = { 1055 url: pdfMakerPrefix + data['logo'] 1056 }; 1057 } 1058 1059 // Generate Content 1060 let myContent = []; 1061 1062 // Logo 1063 if (data['logo']) { 1064 myContent.push({ 1065 image: 'accountLogo', 1066 fit: [(40 * pdfMakerPTsPerMM), (40 * pdfMakerPTsPerMM)], 1067 alignment: 'center' 1068 }); 1069 } 1070 1071 // SubTitle 1072 myContent.push({ 1073 margin: [0, 50, 0, 0], 1074 text: data['subtitleMain'], 1075 style: 'fontSizeNormal', 1076 bold: true, 1077 alignment: 'center' 1078 }); 1079 myContent.push({ 1080 text: data['titleMain'], 1081 style: 'fontSizeBig',
1082 bold: false, 1083 alignment: 'center' 1084 }); 1085 1086 if (language == 'bz') { 1087 myContent.push({ 1088 margin: [0, 5, 0, 15], 1089 canvas: [ 1090 { 1091 type: 'line', 1092 x1: (pdfMakerSettings.border * 2), y1: 0, 1093 x2: (pdfMakerPageSize.a4.p.w - (pdfMakerSettings.border * 4)), y2: 0, 1094 lineWidth: 1, 1095 lineColor: getColor('--color-default-medium') 1096 } 1097 ] 1098 }); 1099 myContent.push({ 1100 text: data['subtitleSecond'], 1101 style: 'fontSizeNormal', 1102 bold: true, 1103 alignment: 'center' 1104 }); 1105 1106 myContent.push({ 1107 text: data['titleSecond'], 1108 style: 'fontSizeBig', 1109 bold: false, 1110 alignment: 'center' 1111 }); 1112 } 1113 myContent.push({ 1114 text: data['validUnit'], 1115 style: 'fontSizeNormal', 1116 bold: true, 1117 alignment: 'center', 1118 margin: (data['logo'] ? [0, 50, 0, 0] : [0, 90, 0, 0]) 1119 }); 1120 1121 myContent.push({ 1122 style: 'fontSizeNormal', 1123 alignment: 'center', 1124 absolutePosition: { x: pdfMakerSettings.border, y: (195 * pdfMakerPTsPerMM) }, 1125 table: { 1126 widths: ['*'], 1127 alignment: 'center', 1128 body: [ 1129 [{ 1130 text: data['subtitleDirs'], 1131 style: 'fontSizeNormal', 1132 bold: true, 1133 alignment: 'center', 1134 }], 1135 [{ 1136 text: data['dirText'], 1137 style: 'fontSizeNormal',
1138 bold: false, 1139 alignment: 'center' 1140 }], 1141 [{ 1142 canvas: [ 1143 { 1144 type: 'line', 1145 x1: (pdfMakerSettings.border * 2), y1: 0, 1146 x2: (pdfMakerPageSize.a4.p.w - (pdfMakerSettings.border * 4)), y2: 0, 1147 lineWidth: 1, 1148 lineColor: getColor('--color-default-medium') 1149 } 1150 ] 1151 }], 1152 [{ 1153 text: data['subtitleInspector'], 1154 style: 'fontSizeNormal', 1155 bold: true, 1156 alignment: 'center' 1157 }], 1158 [{ 1159 text: data['inspectorText'], 1160 style: 'fontSizeNormal', 1161 bold: false, 1162 alignment: 'center' 1163 }] 1164 ] 1165 }, 1166 layout: { defaultBorder: false, paddingLeft: () => 0, paddingRight: () => 0 } 1167 }); 1168 1169 myContent.push({ 1170 absolutePosition: { x: pdfMakerSettings.border, y: (272 * pdfMakerPTsPerMM) }, 1171 columns: [ 1172 { width: '*', text: '' }, 1173 { 1174 style: 'fontSizeNormal', 1175 alignment: 'center', 1176 width: 'auto', 1177 table: { 1178 widths: ['auto', 'auto'], 1179 alignment: 'center', 1180 1181 body: [ 1182 [ 1183 { 1184 text: (translate['TEST']['TITLEPAGE_CREATED_BY'] + (language == 'bz' ? ' / ' + otherTranslate['it']['TEST']['TITLEPAGE_CREATED_BY'] : '')), 1185 alignment: 'right' 1186 }, 1187 { 1188 image: 'logo', 1189 fit: [(23 * pdfMakerPTsPerMM), (5 * pdfMakerPTsPerMM)], 1190 alignment: 'left' 1191 } 1192 ] 1193 ] 1194 }, 1195 layout: 'noBorders' 1196 }, 1197 { width: '*', text: '' } 1198 ] 1199 }); 1200 1201 var docDefinition = { 1202 pageSize: 'A4', 1203 pageOrientation: 'portrait', 1204 compress: true, 1205 pageBreakBefore: true, 1206 pageMargins: [pdfMakerSettings.border, pdfMakerSettings.border, pdfMakerSettings.border, pdfMakerSettings.border], 1207 defaultStyle: { 1208 font: 'montserrat' 1209 }, 1210 images: myImages, 1211 styles: { 1212 fontSizeNormal: { 1213 fontSize: 12, 1214 lineHeight: 1.5 1215 }, 1216 fontSizeBig: { 1217 fontSize: 20, 1218 lineHeight: 1.5 1219 }, 1220 anotherStyle: { 1221 italics: true, 1222 alignment: 'right' 1223 } 1224 }, 1225 content: myContent 1226 }; 1227 const pdfDocGenerator = pdfMake.createPdf(docDefinition); 1228 pdfDocGenerator.getDataUrl((dataUrl) => { 1229 resolve(dataUrl); 1230 }); 1231 }); 1232 1233}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.