1$(document).ready(function() { 2 3 $('#SendDialog').on('show.bs.modal', function(e) { 4 5 setTimeout(function (){ 6 $('#strFileName').focus(); 7 }, 500); 8 9 }); 10 11 $('legend [data-report-option]').click(function(){ 12 13 var strOption = $(this).attr('data-report-option'); 14 15 if($(this).val()=="1") { 16 17 $(this).val("0"); 18 if(typeof updateReport === 'function') updateReport(strOption, false); 19 20 } else { 21 22 $(this).val("1"); 23 if(typeof updateReport === 'function') updateReport(strOption, true); 24 25 } 26 27 }); 28 29 $('[data-report-print]').click(function(e) { 30 e.preventDefault(); 31 printReport($(this).attr('data-report-print')); 32 }); 33 34}); 35 36async function preloadAndDecodeImagesIn(root, timeoutMs = 20000) { 37 const imgs = Array.from(root.querySelectorAll('img')); 38 39 imgs.forEach(img => { 40 img.loading = 'eager'; 41 img.decoding = 'sync'; 42 }); 43 44 // Build absolute URL for fetch WITHOUT changing img.src 45 const absUrl = (img) => { 46 const raw = img.currentSrc || img.getAttribute('src') || img.src || ''; 47 try { return new URL(raw, document.baseURI).href; } catch { return null; } 48 }; 49 50 const prefetched = Promise.all(imgs.map(img => { 51 const url = absUrl(img); 52 if (!url) return Promise.resolve(); 53 return fetch(url, { cache: 'force-cache', mode: 'no-cors' }).catch(() => {}); 54 })); 55 56 const decoded = Promise.all(imgs.map(img => { 57 if (img.decode) return img.decode().catch(() => {}); 58 if (img.complete && img.naturalWidth > 0) return Promise.resolve(); 59 return new Promise(res => { 60 img.addEventListener('load', res, { once: true }); 61 img.addEventListener('error', res, { once: true }); 62 }); 63 })); 64 65 const timeout = new Promise(res => setTimeout(res, timeoutMs)); 66 await Promise.race([Promise.all([prefetched, decoded]), timeout]); 67} 68 69/** 70 * Prints a report or standalone element using an isolated print container. 71 * 72 * The specified element is cloned into a temporary print layer so that only 73 * the desired content appears in the print output. Bootstrap collapse sections 74 * are automatically expanded within the clone, and all images are preloaded 75 * before the print dialog is opened to improve rendering reliability. 76 * 77 * When printing a standalone image (such as from the lightbox), the print 78 * container is marked with the `print-image-only` class, allowing CSS to 79 * centre and scale the image to fit the page. All other content retains the 80 * normal document flow so multi-page reports paginate correctly. 81 * 82 * @param {string} strDivID The ID of the container to print. 83 * @param {string} [strSelector] Optional class name of a descendant element 84 * within the container to print instead. 85 * @returns {Promise<void>} 86 */ 87 88async function printReport(strDivID, strSelector) { 89 90 // Create isolated print container. 91 const printArea = document.createElement('div'); 92 printArea.id = 'print-area'; 93 document.body.appendChild(printArea); 94 95 // Find the source element. 96 const src = document.getElementById(strDivID); 97 98 if(!src) { 99 console.warn('printReport: source element not found:', strDivID); 100 printArea.remove(); 101 return; 102 } 103 104 let node = src; 105 106 if(strSelector) { 107 108 node = src.querySelector('.' + strSelector); 109 110 if(!node) { 111 console.warn('printReport: selector not found:', strSelector); 112 printArea.remove(); 113 return; 114 } 115 116 } 117 118 // Clone the selected content. 119 const clone = node.cloneNode(true); 120 121 // Standalone image printing needs special layout rules. 122 // Normal reports must remain in document flow so they can paginate. 123 if(clone.tagName && clone.tagName.toLowerCase() == 'img') { 124 125 printArea.classList.add('print-image-only'); 126 127 var rotateMatch = clone.style.transform.match(/rotate\([^)]+\)/); 128 129 clone.style.transform = rotateMatch ? rotateMatch[0] : ''; 130 clone.style.transformOrigin = 'center center'; 131 132 } 133 134 printArea.appendChild(clone); 135 136 // If the source or any descendants use Bootstrap collapse classes, 137 // force them open in the print clone so hidden content prints. 138 if(clone.classList.contains('collapse')) { 139 clone.classList.remove('collapse', 'collapsing'); 140 clone.classList.add('show', 'in'); 141 clone.style.display = 'block'; 142 clone.style.height = 'auto'; 143 } 144 145 clone.querySelectorAll('.collapse, .collapsing').forEach(function(el) { 146 el.classList.remove('collapse', 'collapsing'); 147 el.classList.add('show', 'in'); 148 el.style.display = 'block'; 149 el.style.height = 'auto'; 150 }); 151 152 // Apply "printing" class. 153 document.body.classList.add('printing'); 154 155 // Ensure images in the clone are ready before printing. 156 await preloadAndDecodeImagesIn(printArea); 157 158 // Small tick so Chrome's print compositor sees decoded bitmaps. 159 await new Promise(r => requestAnimationFrame(() => setTimeout(r, 0))); 160 161 // Clean up after the dialog closes. 162 const cleanup = () => { 163 document.body.classList.remove('printing'); 164 printArea.remove(); 165 window.removeEventListener('afterprint', cleanup); 166 }; 167 168 window.addEventListener('afterprint', cleanup); 169 170 // Open the dialog. 171 window.print(); 172 173 // Fallback cleanup. 174 setTimeout(() => { 175 if(document.body.classList.contains('printing')) { 176 cleanup(); 177 } 178 }, 30000); 179 180} 181 182function exportReportToMSWordDoc(objForm, strDivID, blnLandscape) { 183 184 var strFileName = $(objForm.strFileName).val(); 185 186 if(!strFileName) return false;
187 188 if(!validateFileName(strFileName)) return false; 189 190 $("body").append('<div id="print-area"></div>'); 191 192 //Copy the element you want to print to the print-me div. 193 $("#" + strDivID).clone().appendTo("#print-area"); 194 195 if($("#" + strDivID)[0].hasAttribute("data-lang")) { 196 197 var enumLang = $("#" + strDivID).attr('data-lang'); 198 199 $('#print-area [data-report-lang]').each(function() { 200 201 if($(this).attr('data-report-lang') !== enumLang) $(this).remove(); 202 203 }); 204 205 $('#print-area .export-hide').each(function() { 206 $(this).remove(); 207 }); 208 209 } 210 211 if(blnLandscape) { 212 213 var header = "<html xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:w=\"urn:schemas-microsoft-com:office:word\" xmlns=\"http://www.w3.org/TR/REC-html40\">"+ 214 "<head><meta charset='utf-8'><title>" + strFileName + "</title>\n"+ 215 "<style>\n"+ 216 "<!--\n"+ 217 "@page mso_landscape { size:792.0pt 612.0pt; mso-page-orientation:landscape; margin:72.0pt 72.0pt 72.0pt 72.0pt; mso-header-margin:35.4pt; mso-footer-margin:35.4pt; mso-paper-source:0; }\n"+ 218 "div.mso_landscape { page: mso_landscape; }\n"+ 219 "-->\n"+ 220 "</style>\n"+ 221 "</head><body>"; 222 223 } else { 224 225 var header = "<html xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:w=\"urn:schemas-microsoft-com:office:word\" xmlns=\"http://www.w3.org/TR/REC-html40\">"+ 226 "<head><meta charset='utf-8'><title>" + strFileName + "</title>\n"+ 227 "<style>\n"+ 228 "<!--\n"+ 229 "@page mso_letter { size:612.0pt 792.0pt; mso-page-orientation:letter; margin:72.0pt 72.0pt 72.0pt 72.0pt; mso-header-margin:35.4pt; mso-footer-margin:35.4pt; mso-paper-source:0; }\n"+ 230 "div.mso_letter { page: mso_letter; }\n"+ 231 "body { font-family: 'Arial', sans-serif; }\n"+ 232 "td { page-break-inside: avoid;}\n"+ 233 "-->\n"+ 234 "</style>\n"+ 235 "<!--[if gte mso 9]><xml>\n"+ 236 "<w:WordDocument>\n"+ 237 "<w:View>Print</w:View>\n"+ 238 "</w:WordDocument>\n"+ 239 "</xml><![endif]--> \n"+ 240 "</head><body>"; 241 242 } 243 244 var footer = "</body></html>"; 245 var sourceHTML = header+document.getElementById('print-area').innerHTML+footer; 246 247 var source = 'data:application/msword;charset=utf-8,' + encodeURIComponent(sourceHTML); 248 var fileDownload = document.createElement("a"); 249 document.body.appendChild(fileDownload); 250 fileDownload.href = source; 251 fileDownload.download = strFileName + '.doc'; 252 fileDownload.click(); 253 document.body.removeChild(fileDownload); 254 255 $("#SaveAsMSWordDialog").modal("hide"); 256 257 // Clear up the div 258 $("#print-area").remove(); 259 260 return false; // prevent submit 261 262}
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.