PageSourceSearch

https://apruo.ca/_scripts/_hi5/hi5-report.js?v=323.8

js apruo.ca collected 2026-10-06 13:06:57 UTC 7,913 bytes, 262 lines download raw bytes

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.