diff --git a/public/resume-5.html b/public/resume-5.html index f694daa..06e4b2e 100644 --- a/public/resume-5.html +++ b/public/resume-5.html @@ -981,28 +981,24 @@ function loadScript(src) { return new Promise(function (ok, fail) { - if (window.html2pdf) { console.log('[PDF] html2pdf already loaded'); ok(); return; } - console.log('[PDF] loading script from CDN...'); + if (window.html2pdf) { ok(); return; } var s = document.createElement('script'); s.src = src; - s.onload = function () { console.log('[PDF] CDN script loaded OK'); ok(); }; - s.onerror = function (e) { console.error('[PDF] CDN script FAILED to load', e); fail(e); }; + s.onload = ok; + s.onerror = fail; document.head.appendChild(s); }); } btn.addEventListener('click', function () { - console.log('[PDF] === click === busy:', busy); if (busy) return; busy = true; btn.setAttribute('data-loading', 'true'); var doc = document.querySelector('.resume-doc'); - console.log('[PDF] doc element:', !!doc, doc ? doc.className : 'N/A'); - if (!doc) { console.error('[PDF] .resume-doc not found!'); busy = false; btn.removeAttribute('data-loading'); return; } + if (!doc) { busy = false; btn.removeAttribute('data-loading'); return; } var photo = doc.querySelector('.resume-photo'); - console.log('[PDF] photo element:', !!photo, photo ? { complete: photo.complete, naturalWidth: photo.naturalWidth, src: photo.src } : 'N/A'); var origSrc = photo ? photo.getAttribute('src') : null; function toDataURL(img) { @@ -1012,64 +1008,81 @@ c.width = img.naturalWidth; c.height = img.naturalHeight; c.getContext('2d').drawImage(img, 0, 0); - var url = c.toDataURL('image/webp'); - console.log('[PDF] toDataURL OK, length:', url.length); - res(url); - } catch (e) { console.error('[PDF] toDataURL FAILED:', e); res(null); } + res(c.toDataURL('image/webp')); + } catch (e) { res(null); } }); } var photoReady; if (photo && photo.complete && photo.naturalWidth > 0) { - console.log('[PDF] photo already loaded, converting...'); photoReady = toDataURL(photo); } else if (photo) { - console.log('[PDF] photo not loaded yet, waiting...'); photoReady = new Promise(function (res) { - photo.onload = function () { console.log('[PDF] photo onload fired'); toDataURL(photo).then(res); }; - photo.onerror = function (e) { console.error('[PDF] photo onerror:', e); res(null); }; + photo.onload = function () { toDataURL(photo).then(res); }; + photo.onerror = function () { res(null); }; }); } else { - console.log('[PDF] no photo element, skipping'); photoReady = Promise.resolve(null); } - function cloneAndInlineStyles(original) { - var clone = original.cloneNode(true); + function resolveStylesInClone(clonedDoc, original) { + 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','content']; + 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']; + var cloneEls = clonedDoc.querySelectorAll('*'); 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); + for (var j = 0; j < props.length; j++) { + var v = cs.getPropertyValue(props[j]); + if (v) cloneEls[i].style.setProperty(props[j], v); } } - 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 rootCs = getComputedStyle(original); + for (var j = 0; j < props.length; j++) { + var v = rootCs.getPropertyValue(props[j]); + if (v) clonedDoc.style.setProperty(props[j], v); + } + + var sheets = clonedDoc.styleSheets; + for (var s = sheets.length - 1; s >= 0; s--) { + try { + var sheet = sheets[s]; + while (sheet.cssRules.length > 0) sheet.deleteRule(0); + } catch (e) {} + } + clonedDoc.querySelectorAll('style').forEach(function (el) { el.remove(); }); + clonedDoc.querySelectorAll('link[rel="stylesheet"]').forEach(function (el) { el.remove(); }); + + var pseudoProps = ['content','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','width','height','border-radius','border-width','border-style','white-space','position','top','bottom','left','right','z-index','overflow','list-style-type','object-fit']; + for (var i = 0; i < origEls.length && i < cloneEls.length; i++) { + ['::before','::after'].forEach(function(pseudo) { + try { + var cs = getComputedStyle(origEls[i], pseudo); + var content = cs.getPropertyValue('content'); + if (!content || content === 'none' || content === 'normal') return; + var el = document.createElement('span'); + el.style.cssText = 'display:block;margin:0;padding:0;border:none;background:none;'; + for (var j = 0; j < pseudoProps.length; j++) { + var v = cs.getPropertyValue(pseudoProps[j]); + if (v && v !== 'normal' && v !== 'auto') el.style.setProperty(pseudoProps[j], v); + } + el.textContent = content.replace(/^["']|["']$/g, ''); + if (pseudo === '::before') cloneEls[i].prepend(el); + else cloneEls[i].appendChild(el); + } catch (e) {} + }); } - 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'); if (dataUrl && photo) photo.setAttribute('src', dataUrl); - console.log('[PDF] step 2: waiting for fonts...'); return document.fonts ? document.fonts.ready : Promise.resolve(); }) .then(function () { - console.log('[PDF] step 3: fonts ready, loading html2pdf.js...'); return loadScript(CDN); }) .then(function () { - console.log('[PDF] step 4: html2pdf loaded, generating...'); return html2pdf().from(doc).set({ margin: 10, filename: 'Mamadaev_Resume.pdf', @@ -1079,41 +1092,21 @@ 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'); + resolveStylesInClone(clonedDoc, doc); } }, jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' } }).save(); }) - .then(function (result) { - console.log('[PDF] step 5: generation COMPLETE, result:', result); + .then(function () { if (origSrc && photo) photo.setAttribute('src', origSrc); busy = false; btn.removeAttribute('data-loading'); }) .catch(function (e) { - console.error('[PDF] step ERROR:', e.message || e); - console.error('[PDF] stack:', e.stack || 'no stack'); + console.error('[PDF] error:', e.message || e, e.stack || ''); if (origSrc && photo) photo.setAttribute('src', origSrc); busy = false; btn.removeAttribute('data-loading'); diff --git a/src/pages/resume-5.html b/src/pages/resume-5.html index 189da70..6277905 100644 --- a/src/pages/resume-5.html +++ b/src/pages/resume-5.html @@ -850,28 +850,24 @@ function loadScript(src) { return new Promise(function (ok, fail) { - if (window.html2pdf) { console.log('[PDF] html2pdf already loaded'); ok(); return; } - console.log('[PDF] loading script from CDN...'); + if (window.html2pdf) { ok(); return; } var s = document.createElement('script'); s.src = src; - s.onload = function () { console.log('[PDF] CDN script loaded OK'); ok(); }; - s.onerror = function (e) { console.error('[PDF] CDN script FAILED to load', e); fail(e); }; + s.onload = ok; + s.onerror = fail; document.head.appendChild(s); }); } btn.addEventListener('click', function () { - console.log('[PDF] === click === busy:', busy); if (busy) return; busy = true; btn.setAttribute('data-loading', 'true'); var doc = document.querySelector('.resume-doc'); - console.log('[PDF] doc element:', !!doc, doc ? doc.className : 'N/A'); - if (!doc) { console.error('[PDF] .resume-doc not found!'); busy = false; btn.removeAttribute('data-loading'); return; } + if (!doc) { busy = false; btn.removeAttribute('data-loading'); return; } var photo = doc.querySelector('.resume-photo'); - console.log('[PDF] photo element:', !!photo, photo ? { complete: photo.complete, naturalWidth: photo.naturalWidth, src: photo.src } : 'N/A'); var origSrc = photo ? photo.getAttribute('src') : null; function toDataURL(img) { @@ -881,64 +877,81 @@ c.width = img.naturalWidth; c.height = img.naturalHeight; c.getContext('2d').drawImage(img, 0, 0); - var url = c.toDataURL('image/webp'); - console.log('[PDF] toDataURL OK, length:', url.length); - res(url); - } catch (e) { console.error('[PDF] toDataURL FAILED:', e); res(null); } + res(c.toDataURL('image/webp')); + } catch (e) { res(null); } }); } var photoReady; if (photo && photo.complete && photo.naturalWidth > 0) { - console.log('[PDF] photo already loaded, converting...'); photoReady = toDataURL(photo); } else if (photo) { - console.log('[PDF] photo not loaded yet, waiting...'); photoReady = new Promise(function (res) { - photo.onload = function () { console.log('[PDF] photo onload fired'); toDataURL(photo).then(res); }; - photo.onerror = function (e) { console.error('[PDF] photo onerror:', e); res(null); }; + photo.onload = function () { toDataURL(photo).then(res); }; + photo.onerror = function () { res(null); }; }); } else { - console.log('[PDF] no photo element, skipping'); photoReady = Promise.resolve(null); } - function cloneAndInlineStyles(original) { - var clone = original.cloneNode(true); + function resolveStylesInClone(clonedDoc, original) { + 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','content']; + 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']; + var cloneEls = clonedDoc.querySelectorAll('*'); 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); + for (var j = 0; j < props.length; j++) { + var v = cs.getPropertyValue(props[j]); + if (v) cloneEls[i].style.setProperty(props[j], v); } } - 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 rootCs = getComputedStyle(original); + for (var j = 0; j < props.length; j++) { + var v = rootCs.getPropertyValue(props[j]); + if (v) clonedDoc.style.setProperty(props[j], v); + } + + var sheets = clonedDoc.styleSheets; + for (var s = sheets.length - 1; s >= 0; s--) { + try { + var sheet = sheets[s]; + while (sheet.cssRules.length > 0) sheet.deleteRule(0); + } catch (e) {} + } + clonedDoc.querySelectorAll('style').forEach(function (el) { el.remove(); }); + clonedDoc.querySelectorAll('link[rel="stylesheet"]').forEach(function (el) { el.remove(); }); + + var pseudoProps = ['content','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','width','height','border-radius','border-width','border-style','white-space','position','top','bottom','left','right','z-index','overflow','list-style-type','object-fit']; + for (var i = 0; i < origEls.length && i < cloneEls.length; i++) { + ['::before','::after'].forEach(function(pseudo) { + try { + var cs = getComputedStyle(origEls[i], pseudo); + var content = cs.getPropertyValue('content'); + if (!content || content === 'none' || content === 'normal') return; + var el = document.createElement('span'); + el.style.cssText = 'display:block;margin:0;padding:0;border:none;background:none;'; + for (var j = 0; j < pseudoProps.length; j++) { + var v = cs.getPropertyValue(pseudoProps[j]); + if (v && v !== 'normal' && v !== 'auto') el.style.setProperty(pseudoProps[j], v); + } + el.textContent = content.replace(/^["']|["']$/g, ''); + if (pseudo === '::before') cloneEls[i].prepend(el); + else cloneEls[i].appendChild(el); + } catch (e) {} + }); } - 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'); if (dataUrl && photo) photo.setAttribute('src', dataUrl); - console.log('[PDF] step 2: waiting for fonts...'); return document.fonts ? document.fonts.ready : Promise.resolve(); }) .then(function () { - console.log('[PDF] step 3: fonts ready, loading html2pdf.js...'); return loadScript(CDN); }) .then(function () { - console.log('[PDF] step 4: html2pdf loaded, generating...'); return html2pdf().from(doc).set({ margin: 10, filename: 'Mamadaev_Resume.pdf', @@ -948,41 +961,21 @@ 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'); + resolveStylesInClone(clonedDoc, doc); } }, jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' } }).save(); }) - .then(function (result) { - console.log('[PDF] step 5: generation COMPLETE, result:', result); + .then(function () { if (origSrc && photo) photo.setAttribute('src', origSrc); busy = false; btn.removeAttribute('data-loading'); }) .catch(function (e) { - console.error('[PDF] step ERROR:', e.message || e); - console.error('[PDF] stack:', e.stack || 'no stack'); + console.error('[PDF] error:', e.message || e, e.stack || ''); if (origSrc && photo) photo.setAttribute('src', origSrc); busy = false; btn.removeAttribute('data-loading');