diff --git a/public/resume-5.html b/public/resume-5.html index bb0c50a..f694daa 100644 --- a/public/resume-5.html +++ b/public/resume-5.html @@ -1034,37 +1034,32 @@ photoReady = Promise.resolve(null); } - function flattenColors(el) { - var s = getComputedStyle(el); - var props = ['color','background-color','border-color','border-top-color','border-bottom-color','border-left-color','border-right-color','box-shadow','background']; - var originals = {}; - props.forEach(function(p) { - var v = s.getPropertyValue(p); - if (v && v.indexOf('color-mix') !== -1) { - originals[p] = el.style.getPropertyValue(p); - el.style.setProperty(p, v); + function cloneAndInlineStyles(original) { + var clone = original.cloneNode(true); + var origEls = original.querySelectorAll('*'); + var cloneEls = clone.querySelectorAll('*'); + var allProps = ['color','background-color','background','border-color','border-top-color','border-bottom-color','border-left-color','border-right-color','box-shadow','opacity','font-family','font-size','font-weight','line-height','letter-spacing','text-align','text-decoration','text-transform','padding','padding-top','padding-bottom','padding-left','padding-right','margin','margin-top','margin-bottom','margin-left','margin-right','display','flex-direction','align-items','justify-content','gap','grid-template-columns','grid-column','width','height','min-width','min-height','max-width','max-height','position','top','bottom','left','right','z-index','overflow','border-radius','border-width','border-style','white-space','list-style-type','object-fit']; + for (var i = 0; i < origEls.length && i < cloneEls.length; i++) { + var cs = getComputedStyle(origEls[i]); + for (var j = 0; j < allProps.length; j++) { + var v = cs.getPropertyValue(allProps[j]); + if (v) cloneEls[i].style.setProperty(allProps[j], v); } - }); - var children = el.children; - for (var i = 0; i < children.length; i++) { - flattenColors(children[i]); } - return originals; - } - - function restoreColors(el, originals) { - Object.keys(originals).forEach(function(p) { - if (originals[p]) el.style.setProperty(p, originals[p]); - else el.style.removeProperty(p); - }); - var children = el.children; - for (var i = 0; i < children.length; i++) { - restoreColors(children[i], originals); + var origCs = getComputedStyle(original); + for (var j = 0; j < allProps.length; j++) { + var v = origCs.getPropertyValue(allProps[j]); + if (v) clone.style.setProperty(allProps[j], v); } + var styles = clone.querySelectorAll('style'); + for (var s = 0; s < styles.length; s++) styles[s].textContent = ''; + var links = clone.querySelectorAll('link[rel="stylesheet"]'); + for (var l = 0; l < links.length; l++) links[l].remove(); + return clone; } photoReady.then(function (dataUrl) { - console.log('[PDF] step 1: photo ready, dataUrl:', dataUrl ? 'yes (' + dataUrl.length + ' chars)' : 'null'); + console.log('[PDF] step 1: photo ready'); if (dataUrl && photo) photo.setAttribute('src', dataUrl); console.log('[PDF] step 2: waiting for fonts...'); return document.fonts ? document.fonts.ready : Promise.resolve(); @@ -1074,19 +1069,41 @@ return loadScript(CDN); }) .then(function () { - console.log('[PDF] step 4: html2pdf loaded, type:', typeof html2pdf); - console.log('[PDF] step 4: flattening color-mix() values...'); - var snapshot = flattenColors(doc); - console.log('[PDF] step 4: starting generation...'); + console.log('[PDF] step 4: html2pdf loaded, generating...'); return html2pdf().from(doc).set({ margin: 10, filename: 'Mamadaev_Resume.pdf', image: { type: 'jpeg', quality: 0.95 }, - html2canvas: { scale: 2, useCORS: true, backgroundColor: '#fff' }, + html2canvas: { + scale: 2, + useCORS: true, + backgroundColor: '#fff', + onclone: function (clonedDoc) { + console.log('[PDF] onclone: inlining styles...'); + var clonedEl = clonedDoc.querySelector('.resume-doc'); + if (!clonedEl) return; + var origEls = doc.querySelectorAll('*'); + var cloneEls = clonedEl.querySelectorAll('*'); + var props = ['color','background-color','background','border-color','border-top-color','border-bottom-color','border-left-color','border-right-color','box-shadow','opacity','font-family','font-size','font-weight','line-height','letter-spacing','text-align','text-decoration','text-transform','padding','padding-top','padding-bottom','padding-left','padding-right','margin','margin-top','margin-bottom','margin-left','margin-right','display','flex-direction','align-items','justify-content','gap','grid-template-columns','grid-column','width','height','min-width','min-height','max-width','max-height','position','top','bottom','left','right','z-index','overflow','border-radius','border-width','border-style','white-space','list-style-type','object-fit']; + for (var i = 0; i < origEls.length && i < cloneEls.length; i++) { + var cs = getComputedStyle(origEls[i]); + for (var j = 0; j < props.length; j++) { + var v = cs.getPropertyValue(props[j]); + if (v) cloneEls[i].style.setProperty(props[j], v); + } + } + var rootCs = getComputedStyle(doc); + for (var j = 0; j < props.length; j++) { + var v = rootCs.getPropertyValue(props[j]); + if (v) clonedEl.style.setProperty(props[j], v); + } + clonedDoc.querySelectorAll('style').forEach(function(s){ s.textContent = ''; }); + clonedDoc.querySelectorAll('link[rel="stylesheet"]').forEach(function(l){ l.remove(); }); + console.log('[PDF] onclone: styles inlined'); + } + }, jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' } - }).save().then(function() { - restoreColors(doc, snapshot); - }); + }).save(); }) .then(function (result) { console.log('[PDF] step 5: generation COMPLETE, result:', result); diff --git a/src/pages/resume-5.html b/src/pages/resume-5.html index f477d6c..189da70 100644 --- a/src/pages/resume-5.html +++ b/src/pages/resume-5.html @@ -903,37 +903,32 @@ photoReady = Promise.resolve(null); } - function flattenColors(el) { - var s = getComputedStyle(el); - var props = ['color','background-color','border-color','border-top-color','border-bottom-color','border-left-color','border-right-color','box-shadow','background']; - var originals = {}; - props.forEach(function(p) { - var v = s.getPropertyValue(p); - if (v && v.indexOf('color-mix') !== -1) { - originals[p] = el.style.getPropertyValue(p); - el.style.setProperty(p, v); + function cloneAndInlineStyles(original) { + var clone = original.cloneNode(true); + var origEls = original.querySelectorAll('*'); + var cloneEls = clone.querySelectorAll('*'); + var allProps = ['color','background-color','background','border-color','border-top-color','border-bottom-color','border-left-color','border-right-color','box-shadow','opacity','font-family','font-size','font-weight','line-height','letter-spacing','text-align','text-decoration','text-transform','padding','padding-top','padding-bottom','padding-left','padding-right','margin','margin-top','margin-bottom','margin-left','margin-right','display','flex-direction','align-items','justify-content','gap','grid-template-columns','grid-column','width','height','min-width','min-height','max-width','max-height','position','top','bottom','left','right','z-index','overflow','border-radius','border-width','border-style','white-space','list-style-type','object-fit']; + for (var i = 0; i < origEls.length && i < cloneEls.length; i++) { + var cs = getComputedStyle(origEls[i]); + for (var j = 0; j < allProps.length; j++) { + var v = cs.getPropertyValue(allProps[j]); + if (v) cloneEls[i].style.setProperty(allProps[j], v); } - }); - var children = el.children; - for (var i = 0; i < children.length; i++) { - flattenColors(children[i]); } - return originals; - } - - function restoreColors(el, originals) { - Object.keys(originals).forEach(function(p) { - if (originals[p]) el.style.setProperty(p, originals[p]); - else el.style.removeProperty(p); - }); - var children = el.children; - for (var i = 0; i < children.length; i++) { - restoreColors(children[i], originals); + var origCs = getComputedStyle(original); + for (var j = 0; j < allProps.length; j++) { + var v = origCs.getPropertyValue(allProps[j]); + if (v) clone.style.setProperty(allProps[j], v); } + var styles = clone.querySelectorAll('style'); + for (var s = 0; s < styles.length; s++) styles[s].textContent = ''; + var links = clone.querySelectorAll('link[rel="stylesheet"]'); + for (var l = 0; l < links.length; l++) links[l].remove(); + return clone; } photoReady.then(function (dataUrl) { - console.log('[PDF] step 1: photo ready, dataUrl:', dataUrl ? 'yes (' + dataUrl.length + ' chars)' : 'null'); + console.log('[PDF] step 1: photo ready'); if (dataUrl && photo) photo.setAttribute('src', dataUrl); console.log('[PDF] step 2: waiting for fonts...'); return document.fonts ? document.fonts.ready : Promise.resolve(); @@ -943,19 +938,41 @@ return loadScript(CDN); }) .then(function () { - console.log('[PDF] step 4: html2pdf loaded, type:', typeof html2pdf); - console.log('[PDF] step 4: flattening color-mix() values...'); - var snapshot = flattenColors(doc); - console.log('[PDF] step 4: starting generation...'); + console.log('[PDF] step 4: html2pdf loaded, generating...'); return html2pdf().from(doc).set({ margin: 10, filename: 'Mamadaev_Resume.pdf', image: { type: 'jpeg', quality: 0.95 }, - html2canvas: { scale: 2, useCORS: true, backgroundColor: '#fff' }, + html2canvas: { + scale: 2, + useCORS: true, + backgroundColor: '#fff', + onclone: function (clonedDoc) { + console.log('[PDF] onclone: inlining styles...'); + var clonedEl = clonedDoc.querySelector('.resume-doc'); + if (!clonedEl) return; + var origEls = doc.querySelectorAll('*'); + var cloneEls = clonedEl.querySelectorAll('*'); + var props = ['color','background-color','background','border-color','border-top-color','border-bottom-color','border-left-color','border-right-color','box-shadow','opacity','font-family','font-size','font-weight','line-height','letter-spacing','text-align','text-decoration','text-transform','padding','padding-top','padding-bottom','padding-left','padding-right','margin','margin-top','margin-bottom','margin-left','margin-right','display','flex-direction','align-items','justify-content','gap','grid-template-columns','grid-column','width','height','min-width','min-height','max-width','max-height','position','top','bottom','left','right','z-index','overflow','border-radius','border-width','border-style','white-space','list-style-type','object-fit']; + for (var i = 0; i < origEls.length && i < cloneEls.length; i++) { + var cs = getComputedStyle(origEls[i]); + for (var j = 0; j < props.length; j++) { + var v = cs.getPropertyValue(props[j]); + if (v) cloneEls[i].style.setProperty(props[j], v); + } + } + var rootCs = getComputedStyle(doc); + for (var j = 0; j < props.length; j++) { + var v = rootCs.getPropertyValue(props[j]); + if (v) clonedEl.style.setProperty(props[j], v); + } + clonedDoc.querySelectorAll('style').forEach(function(s){ s.textContent = ''; }); + clonedDoc.querySelectorAll('link[rel="stylesheet"]').forEach(function(l){ l.remove(); }); + console.log('[PDF] onclone: styles inlined'); + } + }, jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' } - }).save().then(function() { - restoreColors(doc, snapshot); - }); + }).save(); }) .then(function (result) { console.log('[PDF] step 5: generation COMPLETE, result:', result);