@@ -175,71 +175,77 @@ function clearErrors() {
175
175
span . textContent = '' ;
176
176
} ) ;
177
177
}
178
+ function clearErrors ( ) {
179
+ const errorFields = document . querySelectorAll ( ".error-message" ) ;
180
+ errorFields . forEach ( field => field . textContent = "" ) ;
181
+ }
178
182
179
183
function validateForm ( ) {
180
- clearErrors ( ) ; // Clear any existing errors first
184
+ clearErrors ( ) ;
181
185
182
- let isValid = true ; // Assume valid until an error is found
186
+ let isValid = true ;
187
+ let incompleteFields = [ ] ;
183
188
184
- // Validate Full Name: Minimum 3 characters
185
189
const nameInput = document . getElementById ( 'input-name' ) ;
186
190
if ( nameInput . value . trim ( ) . length < 3 ) {
187
191
document . getElementById ( 'error-name' ) . textContent = 'Full Name must be at least 3 characters.' ;
188
192
isValid = false ;
193
+ incompleteFields . push ( "Full Name" ) ;
189
194
}
190
195
191
- // Validate Email: Basic email format (e.g., [email protected] )
192
196
const emailInput = document . getElementById ( 'input-email' ) ;
193
197
const emailPattern = / ^ [ ^ \s @ ] + @ [ ^ \s @ ] + \. [ ^ \s @ ] + $ / ;
194
198
if ( ! emailPattern . test ( emailInput . value . trim ( ) ) ) {
195
199
document . getElementById ( 'error-email' ) . textContent = 'Please enter a valid email address.' ;
196
200
isValid = false ;
201
+ incompleteFields . push ( "Email" ) ;
197
202
}
198
203
199
- // Validate Phone Number: At least 10 digits (allowing optional + and spaces/hyphens)
200
204
const phoneInput = document . getElementById ( 'input-phone' ) ;
201
205
const phonePattern = / ^ \+ ? [ 0 - 9 \s - ] { 10 , } $ / ;
202
206
if ( ! phonePattern . test ( phoneInput . value . trim ( ) ) ) {
203
- document . getElementById ( 'error-phone' ) . textContent = 'Please enter a valid phone number (at least 10 digits) .' ;
207
+ document . getElementById ( 'error-phone' ) . textContent = 'Please enter a valid phone number.' ;
204
208
isValid = false ;
209
+ incompleteFields . push ( "Phone" ) ;
205
210
}
206
211
207
- // Validate LinkedIn Link (optional field, so only validate if value exists)
208
212
const linkedinInput = document . getElementById ( 'input-linkedin' ) ;
209
213
const linkedinPattern = / ^ ( h t t p s ? : \/ \/ ( w w w \. ) ? l i n k e d i n \. c o m \/ i n \/ [ a - z A - Z 0 - 9 _ - ] + \/ ? ) $ / i;
210
214
if ( linkedinInput . value . trim ( ) && ! linkedinPattern . test ( linkedinInput . value . trim ( ) ) ) {
211
- document . getElementById ( 'error-linkedin' ) . textContent = 'Please enter a valid LinkedIn profile URL.' ;
215
+ document . getElementById ( 'error-linkedin' ) . textContent = 'Please enter a valid LinkedIn URL.' ;
212
216
isValid = false ;
217
+ incompleteFields . push ( "LinkedIn" ) ;
213
218
}
214
219
215
- // Validate GitHub Link (optional field, so only validate if value exists)
216
220
const githubInput = document . getElementById ( 'input-github' ) ;
217
221
const githubPattern = / ^ ( h t t p s ? : \/ \/ ( w w w \. ) ? g i t h u b \. c o m \/ [ a - z A - Z 0 - 9 _ - ] + \/ ? ) $ / i;
218
222
if ( githubInput . value . trim ( ) && ! githubPattern . test ( githubInput . value . trim ( ) ) ) {
219
- document . getElementById ( 'error-github' ) . textContent = 'Please enter a valid GitHub profile URL.' ;
223
+ document . getElementById ( 'error-github' ) . textContent = 'Please enter a valid GitHub URL.' ;
220
224
isValid = false ;
225
+ incompleteFields . push ( "GitHub" ) ;
221
226
}
222
227
223
- // Validate Professional Summary: Minimum 50 characters
224
228
const aboutInput = document . getElementById ( 'input-about' ) ;
225
229
if ( aboutInput . value . trim ( ) . length < 50 ) {
226
230
document . getElementById ( 'error-about' ) . textContent = 'Professional Summary should be at least 50 characters.' ;
227
231
isValid = false ;
232
+ incompleteFields . push ( "Professional Summary" ) ;
228
233
}
229
234
230
- return isValid ;
235
+ // If all good, return true
236
+ if ( isValid ) return true ;
237
+
238
+ // Else ask user if they want to proceed anyway
239
+ return confirm ( "Please correct the highlighted errors in the form before downloading your resume." ) ;
231
240
}
232
241
233
242
234
- // --- PDF Download Button ---
243
+
235
244
document . getElementById ( "downloadBtn" ) . addEventListener ( "click" , ( ) => {
236
- // Call validateForm() at the very beginning of the click handler
237
- if ( ! validateForm ( ) ) { // If validation returns false (meaning there are errors)
238
- alert ( "Please correct the highlighted errors in the form before downloading your resume." ) ;
239
- return ; // STOP the function execution here. This prevents the PDF download.
240
- }
245
+ if ( ! validateForm ( ) ) return ;
246
+
247
+ // --- PDF Download Button ---
241
248
242
- // If validation passes (validateForm() returned true), then proceed with download
243
249
const content = document . querySelector ( '#resume-sections' ) ;
244
250
const options = {
245
251
margin : 0.5 ,
@@ -249,44 +255,35 @@ document.getElementById("downloadBtn").addEventListener("click", () => {
249
255
jsPDF : { unit : 'in' , format : 'letter' , orientation : 'portrait' }
250
256
} ;
251
257
html2pdf ( ) . from ( content ) . set ( options ) . save ( ) ;
252
- } ) ;
253
258
259
+ } )
254
260
255
261
// --- DOCX Download Button ---
256
262
document . getElementById ( "downloadDocxBtn" ) . addEventListener ( "click" , ( ) => {
257
- // Call validateForm() at the very beginning of the click handler
258
- if ( ! validateForm ( ) ) { // If validation returns false (meaning there are errors)
259
- alert ( "Please correct the highlighted errors in the form before downloading your resume." ) ;
260
- return ; // STOP the function execution here. This prevents the DOCX download.
261
- }
263
+ if ( ! validateForm ( ) ) return ;
262
264
263
- // If validation passes (validateForm() returned true), then proceed with download
264
265
const resumeContent = document . querySelector ( '#resume-sections' ) . cloneNode ( true ) ;
265
-
266
- // Optional: remove animations if you want cleaner output
267
- resumeContent . querySelectorAll ( ".fade-in, .show" ) . forEach ( el => el . classList . remove ( "fade-in" , "show" ) ) ;
268
-
269
- const html = `
270
- <html xmlns:o='urn:schemas-microsoft-com:office:office'
271
- xmlns:w='urn:schemas-microsoft-com:office:word'
272
- xmlns='http://www.w3.org/TR/REC-html40'>
273
- <head><meta charset='utf-8'><title>Export HTML to Word</title></head>
274
- <body>${ resumeContent . innerHTML } </body>
275
- </html>` ;
266
+ const preHtml = `
267
+ <html>
268
+ <head><meta charset='utf-8'></head>
269
+ <body>` ;
270
+ const postHtml = "</body></html>" ;
271
+ const html = preHtml + resumeContent . innerHTML + postHtml ;
276
272
277
273
const blob = new Blob ( [ '\ufeff' , html ] , {
278
274
type : 'application/msword'
279
275
} ) ;
280
276
281
- const url = URL . createObjectURL ( blob ) ;
282
- const link = document . createElement ( 'a' ) ;
277
+ const url = 'data:application/vnd.ms-word;charset=utf-8,' + encodeURIComponent ( html ) ;
278
+ const link = document . createElement ( "a" ) ;
283
279
link . href = url ;
284
280
link . download = 'resume.doc' ;
285
281
document . body . appendChild ( link ) ;
286
282
link . click ( ) ;
287
283
document . body . removeChild ( link ) ;
288
284
} ) ;
289
285
286
+
290
287
// --- DOMContentLoaded Listener for fade-in animations ---
291
288
document . addEventListener ( "DOMContentLoaded" , ( ) => {
292
289
const observer = new IntersectionObserver ( ( entries , observer ) => {
0 commit comments