';
}
function render(){
var html = buildHtml();
q('[data-rb-preview-box]').innerHTML = html;
q('[data-rb-preview-wrap]').style.display = 'flex';
}
function syncPrintSheet(){
var html = buildHtml();
var printBox = root.parentElement.querySelector('[data-rb-print-box]') || document.querySelector('[data-rb-print-box]');
if (printBox) printBox.innerHTML = html;
}
function initTemplates(){
q('[data-rb-templates]').innerHTML = TEMPLATES.map(function(t){
return '';
}).join('');
qa('.rb-template').forEach(function(btn){
btn.addEventListener('click', function(){
activeTemplate = btn.dataset.t;
initTemplates();
render();
});
});
}
function bindPhotoInput(input){
input.addEventListener('change', function(){
var file = this.files[0];
if (!file) return;
var reader = new FileReader();
reader.onload = function(){
photoData = reader.result;
var box = q('[data-rb-photo-box]');
box.innerHTML = '';
bindPhotoInput(box.querySelector('input'));
};
reader.readAsDataURL(file);
});
}
q('[data-rb-add-qual]').addEventListener('click', function(){ addQualRow(); });
q('[data-rb-add-exp]').addEventListener('click', function(){ addExpRow(); });
q('[data-rb-preview]').addEventListener('click', render);
// Print Resume: fills the hidden off-screen A4 sheet, then opens the
// browser print dialog. The @media print CSS hides everything else on
// the page (including any surrounding site header/nav/footer) so only
// the A4 resume prints.
q('[data-rb-print]').addEventListener('click', function(){
render();
syncPrintSheet();
window.print();
});
// Download Resume (PDF): rasterizes the same off-screen A4 sheet with
// html2canvas and saves it as a single-page A4 PDF via jsPDF, without
// involving the browser's print dialog at all.
q('[data-rb-download]').addEventListener('click', function(){
var btn = q('[data-rb-download]');
var originalText = btn.textContent;
btn.disabled = true;
btn.textContent = 'Generating PDF…';
render();
syncPrintSheet();
var sheet = document.querySelector('[data-rb-print-sheet]');
var page = sheet.querySelector('.rb-page');
window.html2canvas(page, { scale: 2, useCORS: true, backgroundColor: '#ffffff' }).then(function(canvas){
var imgData = canvas.toDataURL('image/jpeg', 0.95);
var jsPDF = window.jspdf.jsPDF;
var pdf = new jsPDF('p', 'mm', 'a4');
// The resume can be taller than one A4 page. Scale the captured
// image to the PDF's 210mm width, then slice it into as many
// 297mm-tall pages as needed so nothing gets cut off.
var pageWidthMM = 210, pageHeightMM = 297;
var imgWidthMM = pageWidthMM;
var imgHeightMM = (canvas.height * imgWidthMM) / canvas.width;
var heightLeft = imgHeightMM;
var position = 0;
pdf.addImage(imgData, 'JPEG', 0, position, imgWidthMM, imgHeightMM);
heightLeft -= pageHeightMM;
while (heightLeft > 0) {
position = heightLeft - imgHeightMM;
pdf.addPage();
pdf.addImage(imgData, 'JPEG', 0, position, imgWidthMM, imgHeightMM);
heightLeft -= pageHeightMM;
}
var name = (val('fullName') || 'Resume').trim().replace(/\s+/g, '_') || 'Resume';
pdf.save(name + '_Resume.pdf');
}).catch(function(err){
console.error('PDF generation failed:', err);
alert('Sorry, PDF generation failed. Please try the Print Resume button instead.');
}).finally(function(){
btn.disabled = false;
btn.textContent = originalText;
});
});
q('[data-rb-reset]').addEventListener('click', function(){
if (confirm('Reset the whole resume form?')) location.reload();
});
bindPhotoInput(q('[data-rb-photo]'));
initTemplates();
addQualRow();
addExpRow();
});
})();