← All changes
|
includes/widgets/Pricing_Calculator/script.js
+113
-223
51.1.38
→
51.1.86
View file →
| @@ -36,9 +36,9 @@ | ||
| 36 | 36 | var $summaryItems = $calculator.find('.king-pricing-calculator__summary-items'); |
| 37 | 37 | var $calculateButton = $calculator.find('.king-pricing-calculator__calculate-button'); |
| 38 | 38 | |
| 39 | 39 | // Debug info - log initial calculator settings |
| 40 | - console.log('Calculator initialized with base price:', basePrice); | |
| 40 | + // console.log('Calculator initialized with base price:', basePrice); | |
| 41 | 41 | |
| 42 | 42 | // Get ajaxurl from localized script if it exists, fallback to global |
| 43 | 43 | var ajaxUrl = (typeof king_addons_calculator_vars !== 'undefined') ? king_addons_calculator_vars.ajaxurl : (typeof ajaxurl !== 'undefined' ? ajaxurl : ''); |
| 44 | 44 | // Get nonces from localized script |
| @@ -55,8 +55,23 @@ | ||
| 55 | 55 | func.apply(context, args); |
| 56 | 56 | }, wait); |
| 57 | 57 | }; |
| 58 | 58 | }; |
| 59 | + | |
| 60 | + // Sanitize potentially user-controlled strings before inserting into HTML. | |
| 61 | + // Uses DOMPurify for robust XSS protection. | |
| 62 | + var sanitizeHtml = function(value) { | |
| 63 | + if (typeof DOMPurify !== 'undefined') { | |
| 64 | + return DOMPurify.sanitize(String(value), {ALLOWED_TAGS: [], ALLOWED_ATTR: []}); | |
| 65 | + } | |
| 66 | + // Fallback if DOMPurify not loaded | |
| 67 | + return String(value) | |
| 68 | + .replace(/&/g, '&') | |
| 69 | + .replace(/</g, '<') | |
| 70 | + .replace(/>/g, '>') | |
| 71 | + .replace(/"/g, '"') | |
| 72 | + .replace(/'/g, '''); | |
| 73 | + }; | |
| 59 | 74 | |
| 60 | 75 | // Initialize field values and events |
| 61 | 76 | initFields($fields); |
| 62 | 77 | |
| @@ -108,15 +123,15 @@ | ||
| 108 | 123 | var $field = $(this); |
| 109 | 124 | var fieldType = $field.data('field-type'); |
| 110 | 125 | |
| 111 | 126 | // Debug info - log field attributes |
| 112 | - console.log('Field:', fieldType, 'Price Type:', $field.data('price-type'), 'Price:', $field.data('price')); | |
| 127 | + // console.log('Field:', fieldType, 'Price Type:', $field.data('price-type'), 'Price:', $field.data('price')); | |
| 113 | 128 | |
| 114 | 129 | // Check if custom formula is used (Pro feature) |
| 115 | 130 | if ($field.data('price-type') === 'custom') { |
| 116 | 131 | // Show a one-time console message |
| 117 | 132 | if (!window.customFormulaMessageShown) { |
| 118 | - console.info('Custom formula calculation requires Pro version.'); | |
| 133 | + // console.info('Custom formula calculation requires Pro version.'); | |
| 119 | 134 | window.customFormulaMessageShown = true; |
| 120 | 135 | } |
| 121 | 136 | } |
| 122 | 137 | |
| @@ -223,8 +238,10 @@ | ||
| 223 | 238 | } |
| 224 | 239 | |
| 225 | 240 | /** |
| 226 | 241 | * Calculate the total price based on all field values |
| 242 | + * Fields are processed in DOM order, applying each operation sequentially. | |
| 243 | + * This allows for proper calculation order (e.g., multiply first two values, then add third). | |
| 227 | 244 | */ |
| 228 | 245 | function calculatePrice() { |
| 229 | 246 | try { |
| 230 | 247 | // Start with base price |
| @@ -231,13 +248,13 @@ | ||
| 231 | 248 | var total = basePrice; |
| 232 | 249 | var summaryHtml = ''; |
| 233 | 250 | |
| 234 | 251 | // Debug info |
| 235 | - console.log('Starting calculation with base price:', total); | |
| 252 | + // console.log('Starting calculation with base price:', total); | |
| 236 | 253 | |
| 237 | 254 | // Advanced Formula will be applied after default calculation |
| 238 | 255 | |
| 239 | - // First handle additions | |
| 256 | + // Process all fields in DOM order (sequential calculation) | |
| 240 | 257 | $fields.each(function() { |
| 241 | 258 | var $field = $(this); |
| 242 | 259 | var fieldType = $field.data('field-type'); |
| 243 | 260 | var priceType = $field.data('price-type'); |
| @@ -244,24 +261,17 @@ | ||
| 244 | 261 | var fieldLabel = $field.find('.king-pricing-calculator__field-label').text(); |
| 245 | 262 | var fieldValue = 0; |
| 246 | 263 | var fieldPrice = 0; |
| 247 | 264 | var subTotal = 0; |
| 265 | + var beforeOp = total; | |
| 248 | 266 | |
| 249 | - if (priceType !== 'add') { | |
| 250 | - return; // Skip non-addition fields on first pass | |
| 251 | - } | |
| 252 | - | |
| 253 | 267 | try { |
| 268 | + // Get field value and price based on field type | |
| 254 | 269 | switch (fieldType) { |
| 255 | 270 | case 'number': |
| 256 | 271 | var $input = $field.find('input[type="number"]'); |
| 257 | 272 | fieldValue = parseFloat($input.val()); |
| 258 | 273 | fieldPrice = parseFloat($field.data('price')); |
| 259 | - | |
| 260 | - if (!isNaN(fieldValue) && !isNaN(fieldPrice)) { | |
| 261 | - subTotal = fieldValue * fieldPrice; | |
| 262 | - total += subTotal; | |
| 263 | - } | |
| 264 | 274 | break; |
| 265 | 275 | |
| 266 | 276 | case 'range': |
| 267 | 277 | var $range = $field.find('input[type="range"]'); |
| @@ -266,39 +276,22 @@ | ||
| 266 | 276 | case 'range': |
| 267 | 277 | var $range = $field.find('input[type="range"]'); |
| 268 | 278 | fieldValue = parseFloat($range.val()); |
| 269 | 279 | fieldPrice = parseFloat($field.data('price')); |
| 270 | - | |
| 271 | - if (!isNaN(fieldValue) && !isNaN(fieldPrice)) { | |
| 272 | - subTotal = fieldValue * fieldPrice; | |
| 273 | - total += subTotal; | |
| 274 | - } | |
| 275 | 280 | break; |
| 276 | 281 | |
| 277 | 282 | case 'select': |
| 278 | 283 | var $select = $field.find('select'); |
| 279 | 284 | var $option = $select.find('option:selected'); |
| 280 | - | |
| 281 | 285 | fieldValue = $option.text(); |
| 282 | 286 | fieldPrice = parseFloat($option.data('price')); |
| 283 | - | |
| 284 | - if (!isNaN(fieldPrice)) { | |
| 285 | - subTotal = fieldPrice; | |
| 286 | - total += subTotal; | |
| 287 | - } | |
| 288 | 287 | break; |
| 289 | 288 | |
| 290 | 289 | case 'radio': |
| 291 | 290 | var $radio = $field.find('input[type="radio"]:checked'); |
| 292 | - | |
| 293 | 291 | if ($radio.length) { |
| 294 | 292 | fieldValue = $radio.siblings('label').text(); |
| 295 | 293 | fieldPrice = parseFloat($radio.data('price')); |
| 296 | - | |
| 297 | - if (!isNaN(fieldPrice)) { | |
| 298 | - subTotal = fieldPrice; | |
| 299 | - total += subTotal; | |
| 300 | - } | |
| 301 | 294 | } |
| 302 | 295 | break; |
| 303 | 296 | |
| 304 | 297 | case 'checkbox': |
| @@ -303,207 +296,104 @@ | ||
| 303 | 296 | |
| 304 | 297 | case 'checkbox': |
| 305 | 298 | case 'switch': |
| 306 | 299 | var $checkbox = $field.find('input[type="checkbox"]'); |
| 307 | - | |
| 308 | 300 | if ($checkbox.is(':checked')) { |
| 309 | 301 | fieldValue = 'Yes'; |
| 310 | 302 | fieldPrice = parseFloat($field.data('price')); |
| 311 | - | |
| 312 | - if (!isNaN(fieldPrice)) { | |
| 313 | - subTotal = fieldPrice; | |
| 314 | - total += subTotal; | |
| 315 | - } | |
| 316 | 303 | } else { |
| 317 | 304 | fieldValue = 'No'; |
| 305 | + fieldPrice = 0; | |
| 318 | 306 | } |
| 319 | 307 | break; |
| 320 | 308 | } |
| 321 | 309 | |
| 322 | - // Add to summary if there's a value and subtotal | |
| 323 | - if (fieldValue !== '' && fieldValue !== 0 && subTotal !== 0) { | |
| 324 | - summaryHtml += '<div class="king-pricing-calculator__summary-item">' + | |
| 325 | - '<span class="king-pricing-calculator__summary-label">' + fieldLabel + ': ' + fieldValue + '</span>' + | |
| 326 | - '<span class="king-pricing-calculator__summary-value">' + formatPrice(subTotal) + '</span>' + | |
| 327 | - '</div>'; | |
| 328 | - } | |
| 329 | - | |
| 330 | - // Debug info | |
| 331 | - console.log('Field:', fieldLabel, 'Type:', fieldType, 'Value:', fieldValue, 'Price:', fieldPrice, 'Subtotal:', subTotal); | |
| 332 | - | |
| 333 | - } catch (fieldError) { | |
| 334 | - console.error('Error processing field for addition:', fieldError); | |
| 335 | - } | |
| 336 | - }); | |
| 337 | - | |
| 338 | - // Debug info | |
| 339 | - console.log('After additions, total is:', total); | |
| 340 | - | |
| 341 | - // Then handle multiplications | |
| 342 | - $fields.each(function() { | |
| 343 | - var $field = $(this); | |
| 344 | - var fieldType = $field.data('field-type'); | |
| 345 | - var priceType = $field.data('price-type'); | |
| 346 | - var fieldLabel = $field.find('.king-pricing-calculator__field-label').text(); | |
| 347 | - var fieldValue = 0; | |
| 348 | - var fieldPrice = 0; | |
| 349 | - var beforeMult = total; | |
| 350 | - | |
| 351 | - if (priceType !== 'multiply') { | |
| 352 | - return; // Skip non-multiplication fields on second pass | |
| 353 | - } | |
| 354 | - | |
| 355 | - try { | |
| 356 | - switch (fieldType) { | |
| 357 | - case 'number': | |
| 358 | - var $input = $field.find('input[type="number"]'); | |
| 359 | - fieldValue = parseFloat($input.val()); | |
| 360 | - | |
| 361 | - if (!isNaN(fieldValue) && fieldValue !== 0) { | |
| 362 | - beforeMult = total; | |
| 363 | - total *= fieldValue; | |
| 364 | - | |
| 365 | - summaryHtml += '<div class="king-pricing-calculator__summary-item">' + | |
| 366 | - '<span class="king-pricing-calculator__summary-label">' + fieldLabel + ': ' + fieldValue + '</span>' + | |
| 367 | - '<span class="king-pricing-calculator__summary-value">' + formatPrice(total - beforeMult) + '</span>' + | |
| 368 | - '</div>'; | |
| 310 | + // Apply the operation based on price type | |
| 311 | + if (priceType === 'add') { | |
| 312 | + // For number/range: multiply value by price per unit, then add | |
| 313 | + if (fieldType === 'number' || fieldType === 'range') { | |
| 314 | + if (!isNaN(fieldValue) && !isNaN(fieldPrice)) { | |
| 315 | + subTotal = fieldValue * fieldPrice; | |
| 316 | + total += subTotal; | |
| 369 | 317 | } |
| 370 | - break; | |
| 371 | - | |
| 372 | - case 'range': | |
| 373 | - var $range = $field.find('input[type="range"]'); | |
| 374 | - fieldValue = parseFloat($range.val()); | |
| 375 | - | |
| 318 | + } else { | |
| 319 | + // For select/radio/checkbox: add the price directly | |
| 320 | + if (!isNaN(fieldPrice)) { | |
| 321 | + subTotal = fieldPrice; | |
| 322 | + total += subTotal; | |
| 323 | + } | |
| 324 | + } | |
| 325 | + | |
| 326 | + // Add to summary if there's a contribution | |
| 327 | + if (subTotal !== 0) { | |
| 328 | + summaryHtml += '<div class="king-pricing-calculator__summary-item">' + | |
| 329 | + '<span class="king-pricing-calculator__summary-label">' + sanitizeHtml(fieldLabel) + ': ' + sanitizeHtml(fieldValue) + '</span>' + | |
| 330 | + '<span class="king-pricing-calculator__summary-value">+' + sanitizeHtml(formatPrice(subTotal)) + '</span>' + | |
| 331 | + '</div>'; | |
| 332 | + } | |
| 333 | + | |
| 334 | + // console.log('Field (add):', fieldLabel, 'Value:', fieldValue, 'Price:', fieldPrice, 'Subtotal:', subTotal, 'Total:', total); | |
| 335 | + | |
| 336 | + } else if (priceType === 'multiply') { | |
| 337 | + // For number/range: multiply total by the field value | |
| 338 | + if (fieldType === 'number' || fieldType === 'range') { | |
| 376 | 339 | if (!isNaN(fieldValue) && fieldValue !== 0) { |
| 377 | - beforeMult = total; | |
| 340 | + beforeOp = total; | |
| 378 | 341 | total *= fieldValue; |
| 379 | 342 | |
| 380 | 343 | summaryHtml += '<div class="king-pricing-calculator__summary-item">' + |
| 381 | - '<span class="king-pricing-calculator__summary-label">' + fieldLabel + ': ' + fieldValue + '</span>' + | |
| 382 | - '<span class="king-pricing-calculator__summary-value">' + formatPrice(total - beforeMult) + '</span>' + | |
| 344 | + '<span class="king-pricing-calculator__summary-label">' + sanitizeHtml(fieldLabel) + ': ×' + sanitizeHtml(fieldValue) + '</span>' + | |
| 345 | + '<span class="king-pricing-calculator__summary-value">' + sanitizeHtml(formatPrice(total - beforeOp)) + '</span>' + | |
| 383 | 346 | '</div>'; |
| 384 | 347 | } |
| 385 | - break; | |
| 386 | - | |
| 387 | - case 'select': | |
| 388 | - var $select = $field.find('select'); | |
| 389 | - var $option = $select.find('option:selected'); | |
| 390 | - | |
| 391 | - fieldValue = $option.text(); | |
| 392 | - fieldPrice = parseFloat($option.data('price')); | |
| 393 | - | |
| 348 | + } else { | |
| 349 | + // For select/radio/checkbox: multiply total by the price | |
| 394 | 350 | if (!isNaN(fieldPrice) && fieldPrice !== 0) { |
| 395 | - beforeMult = total; | |
| 351 | + beforeOp = total; | |
| 396 | 352 | total *= fieldPrice; |
| 397 | 353 | |
| 398 | 354 | summaryHtml += '<div class="king-pricing-calculator__summary-item">' + |
| 399 | - '<span class="king-pricing-calculator__summary-label">' + fieldLabel + ': ' + fieldValue + '</span>' + | |
| 400 | - '<span class="king-pricing-calculator__summary-value">' + formatPrice(total - beforeMult) + '</span>' + | |
| 355 | + '<span class="king-pricing-calculator__summary-label">' + sanitizeHtml(fieldLabel) + ': ' + sanitizeHtml(fieldValue) + ' (×' + sanitizeHtml(fieldPrice) + ')</span>' + | |
| 356 | + '<span class="king-pricing-calculator__summary-value">' + sanitizeHtml(formatPrice(total - beforeOp)) + '</span>' + | |
| 401 | 357 | '</div>'; |
| 402 | 358 | } |
| 403 | - break; | |
| 404 | - | |
| 405 | - case 'radio': | |
| 406 | - var $radio = $field.find('input[type="radio"]:checked'); | |
| 407 | - | |
| 408 | - if ($radio.length) { | |
| 409 | - fieldValue = $radio.siblings('label').text(); | |
| 410 | - fieldPrice = parseFloat($radio.data('price')); | |
| 411 | - | |
| 412 | - if (!isNaN(fieldPrice) && fieldPrice !== 0) { | |
| 413 | - beforeMult = total; | |
| 414 | - total *= fieldPrice; | |
| 415 | - | |
| 416 | - summaryHtml += '<div class="king-pricing-calculator__summary-item">' + | |
| 417 | - '<span class="king-pricing-calculator__summary-label">' + fieldLabel + ': ' + fieldValue + '</span>' + | |
| 418 | - '<span class="king-pricing-calculator__summary-value">' + formatPrice(total - beforeMult) + '</span>' + | |
| 419 | - '</div>'; | |
| 420 | - } | |
| 421 | - } | |
| 422 | - break; | |
| 423 | - | |
| 424 | - case 'checkbox': | |
| 425 | - case 'switch': | |
| 426 | - var $checkbox = $field.find('input[type="checkbox"]'); | |
| 427 | - | |
| 428 | - if ($checkbox.is(':checked')) { | |
| 429 | - fieldValue = 'Yes'; | |
| 430 | - fieldPrice = parseFloat($field.data('price')); | |
| 431 | - | |
| 432 | - if (!isNaN(fieldPrice) && fieldPrice !== 0) { | |
| 433 | - beforeMult = total; | |
| 434 | - total *= fieldPrice; | |
| 435 | - | |
| 436 | - summaryHtml += '<div class="king-pricing-calculator__summary-item">' + | |
| 437 | - '<span class="king-pricing-calculator__summary-label">' + fieldLabel + ': ' + fieldValue + '</span>' + | |
| 438 | - '<span class="king-pricing-calculator__summary-value">' + formatPrice(total - beforeMult) + '</span>' + | |
| 439 | - '</div>'; | |
| 440 | - } | |
| 441 | - } | |
| 442 | - break; | |
| 443 | - } | |
| 444 | - | |
| 445 | - // Debug info | |
| 446 | - console.log('Field (multiply):', fieldLabel, 'Type:', fieldType, 'Value:', fieldValue, 'BeforeMult:', beforeMult, 'After:', total); | |
| 447 | - | |
| 448 | - } catch (fieldError) { | |
| 449 | - console.error('Error processing field for multiplication:', fieldError); | |
| 450 | - } | |
| 451 | - }); | |
| 452 | - | |
| 453 | - // Then handle custom formula (fallback to addition in free version) | |
| 454 | - $fields.each(function() { | |
| 455 | - var $field = $(this); | |
| 456 | - var fieldType = $field.data('field-type'); | |
| 457 | - var priceType = $field.data('price-type'); | |
| 458 | - | |
| 459 | - if (priceType !== 'custom') { | |
| 460 | - return; // Skip non-custom fields | |
| 461 | - } | |
| 462 | - | |
| 463 | - try { | |
| 464 | - // In the free version, just treat custom formula as add | |
| 465 | - var fieldLabel = $field.find('.king-pricing-calculator__field-label').text(); | |
| 466 | - var fieldValue, fieldPrice, subTotal = 0; | |
| 467 | - | |
| 468 | - switch (fieldType) { | |
| 469 | - case 'number': | |
| 470 | - case 'range': | |
| 471 | - var $input = fieldType === 'number' ? | |
| 472 | - $field.find('input[type="number"]') : | |
| 473 | - $field.find('input[type="range"]'); | |
| 474 | - | |
| 475 | - fieldValue = parseFloat($input.val()); | |
| 476 | - fieldPrice = parseFloat($field.data('price')); | |
| 477 | - | |
| 359 | + } | |
| 360 | + | |
| 361 | + // console.log('Field (multiply):', fieldLabel, 'Value:', fieldValue, 'BeforeOp:', beforeOp, 'Total:', total); | |
| 362 | + | |
| 363 | + } else if (priceType === 'custom') { | |
| 364 | + // In the free version, treat custom formula as add (fallback) | |
| 365 | + if (fieldType === 'number' || fieldType === 'range') { | |
| 478 | 366 | if (!isNaN(fieldValue) && !isNaN(fieldPrice)) { |
| 479 | - // Fallback to addition in free version | |
| 480 | 367 | subTotal = fieldValue * fieldPrice; |
| 481 | 368 | total += subTotal; |
| 482 | 369 | |
| 483 | 370 | summaryHtml += '<div class="king-pricing-calculator__summary-item">' + |
| 484 | 371 | '<span class="king-pricing-calculator__summary-label">' + |
| 485 | - fieldLabel + ': ' + fieldValue + | |
| 372 | + sanitizeHtml(fieldLabel) + ': ' + sanitizeHtml(fieldValue) + | |
| 486 | 373 | ' <small>(Pro formula fallback)</small>' + |
| 487 | 374 | '</span>' + |
| 488 | - '<span class="king-pricing-calculator__summary-value">' + formatPrice(subTotal) + '</span>' + | |
| 375 | + '<span class="king-pricing-calculator__summary-value">' + sanitizeHtml(formatPrice(subTotal)) + '</span>' + | |
| 489 | 376 | '</div>'; |
| 490 | 377 | } |
| 491 | - break; | |
| 378 | + } else if (!isNaN(fieldPrice)) { | |
| 379 | + subTotal = fieldPrice; | |
| 380 | + total += subTotal; | |
| 492 | 381 | |
| 493 | - case 'select': | |
| 494 | - case 'radio': | |
| 495 | - case 'checkbox': | |
| 496 | - case 'switch': | |
| 497 | - // Handle similar to add, with pro notice | |
| 498 | - // Implementation follows similar pattern to the addition case | |
| 499 | - break; | |
| 382 | + summaryHtml += '<div class="king-pricing-calculator__summary-item">' + | |
| 383 | + '<span class="king-pricing-calculator__summary-label">' + | |
| 384 | + sanitizeHtml(fieldLabel) + ': ' + sanitizeHtml(fieldValue) + | |
| 385 | + ' <small>(Pro formula fallback)</small>' + | |
| 386 | + '</span>' + | |
| 387 | + '<span class="king-pricing-calculator__summary-value">' + sanitizeHtml(formatPrice(subTotal)) + '</span>' + | |
| 388 | + '</div>'; | |
| 389 | + } | |
| 390 | + | |
| 391 | + // console.log('Field (custom/fallback):', fieldLabel, 'Added:', subTotal, 'Total:', total); | |
| 500 | 392 | } |
| 501 | - | |
| 502 | - console.log('Custom formula field (free fallback):', fieldLabel, 'Added:', subTotal); | |
| 503 | - | |
| 393 | + | |
| 504 | 394 | } catch (fieldError) { |
| 505 | - console.error('Error processing custom formula field:', fieldError); | |
| 395 | + // console.error('Error processing field:', fieldLabel, fieldError); | |
| 506 | 396 | } |
| 507 | 397 | }); |
| 508 | 398 | |
| 509 | 399 | // Advanced Formula override (Pro) after default calculation loops |
| @@ -535,10 +425,10 @@ | ||
| 535 | 425 | } |
| 536 | 426 | }); |
| 537 | 427 | |
| 538 | 428 | // For debugging custom formulas |
| 539 | - console.log('Available field IDs:', fieldsMap); | |
| 540 | - console.log('User-friendly field aliases:', aliasMap); | |
| 429 | + // console.log('Available field IDs:', fieldsMap); | |
| 430 | + // console.log('User-friendly field aliases:', aliasMap); | |
| 541 | 431 | |
| 542 | 432 | // Apply chosen formula on the aggregated total |
| 543 | 433 | var newTotal = total; |
| 544 | 434 | if (formulaType === 'exponential') { |
| @@ -552,9 +442,9 @@ | ||
| 552 | 442 | var customCode = $calculator.data('customFormula') || ''; |
| 553 | 443 | try { |
| 554 | 444 | // Security fix: Only allow safe mathematical operations |
| 555 | 445 | if (!isCustomFormulaSafe(customCode)) { |
| 556 | - console.error('Custom formula contains unsafe code'); | |
| 446 | + // console.error('Custom formula contains unsafe code'); | |
| 557 | 447 | return; |
| 558 | 448 | } |
| 559 | 449 | // Pass both the full field map and user-friendly aliases |
| 560 | 450 | var fn = new Function('fields', 'basePrice', 'aliases', customCode); |
| @@ -559,9 +449,9 @@ | ||
| 559 | 449 | // Pass both the full field map and user-friendly aliases |
| 560 | 450 | var fn = new Function('fields', 'basePrice', 'aliases', customCode); |
| 561 | 451 | newTotal = fn(fieldsMap, basePrice, aliasMap); |
| 562 | 452 | } catch (e) { |
| 563 | - console.error('Custom formula error:', e); | |
| 453 | + // console.error('Custom formula error:', e); | |
| 564 | 454 | } |
| 565 | 455 | |
| 566 | 456 | function isCustomFormulaSafe(formula) { |
| 567 | 457 | // Only allow safe mathematical operations |
| @@ -597,14 +487,14 @@ | ||
| 597 | 487 | } |
| 598 | 488 | |
| 599 | 489 | // Final check to prevent NaN |
| 600 | 490 | if (isNaN(total)) { |
| 601 | - console.error('Total calculation resulted in NaN'); | |
| 491 | + // console.error('Total calculation resulted in NaN'); | |
| 602 | 492 | total = basePrice; |
| 603 | 493 | } |
| 604 | 494 | |
| 605 | 495 | // Debug info |
| 606 | - console.log('Final total:', total); | |
| 496 | + // console.log('Final total:', total); | |
| 607 | 497 | |
| 608 | 498 | // Update the total price |
| 609 | 499 | $totalPrice.text(formatPrice(total)); |
| 610 | 500 | |
| @@ -610,9 +500,9 @@ | ||
| 610 | 500 | |
| 611 | 501 | // Update the summary items |
| 612 | 502 | $summaryItems.html(summaryHtml); |
| 613 | 503 | } catch(e) { |
| 614 | - console.error('Calculation error:', e); | |
| 504 | + // console.error('Calculation error:', e); | |
| 615 | 505 | $totalPrice.text(formatPrice(basePrice)); |
| 616 | 506 | } |
| 617 | 507 | } |
| 618 | 508 | |
| @@ -620,9 +510,9 @@ | ||
| 620 | 510 | * Format a price number with proper separators |
| 621 | 511 | */ |
| 622 | 512 | function formatPrice(number) { |
| 623 | 513 | if (isNaN(number)) { |
| 624 | - console.error('Attempting to format NaN as price'); | |
| 514 | + // console.error('Attempting to format NaN as price'); | |
| 625 | 515 | number = 0; |
| 626 | 516 | } |
| 627 | 517 | var parts = number.toFixed(decimalPlaces).toString().split('.'); |
| 628 | 518 | parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, thousandSeparator); |
| @@ -666,15 +556,15 @@ | ||
| 666 | 556 | conditionalRules = $calculator.data('conditionalRules'); |
| 667 | 557 | |
| 668 | 558 | // If that doesn't work, try to get the raw attribute and parse it |
| 669 | 559 | if (!conditionalRules && $calculator.attr('data-conditional-rules')) { |
| 670 | - console.log('Found data-conditional-rules attribute, trying to parse:', $calculator.attr('data-conditional-rules')); | |
| 560 | + // console.log('Found data-conditional-rules attribute, trying to parse:', $calculator.attr('data-conditional-rules')); | |
| 671 | 561 | conditionalRules = JSON.parse($calculator.attr('data-conditional-rules')); |
| 672 | 562 | } |
| 673 | 563 | |
| 674 | - console.log('Conditional rules loaded:', conditionalRules); | |
| 564 | + // console.log('Conditional rules loaded:', conditionalRules); | |
| 675 | 565 | } catch (e) { |
| 676 | - console.error('Error parsing conditional rules:', e); | |
| 566 | + // console.error('Error parsing conditional rules:', e); | |
| 677 | 567 | } |
| 678 | 568 | |
| 679 | 569 | // Add to Cart Integration |
| 680 | 570 | $calculator.find('.king-pricing-calculator-pro__add-to-cart-button').on('click', function() { |
| @@ -856,9 +746,9 @@ | ||
| 856 | 746 | // Save to localStorage |
| 857 | 747 | localStorage.setItem(storageKey, JSON.stringify(fieldsData)); |
| 858 | 748 | alert('Calculation saved successfully.'); |
| 859 | 749 | } catch (error) { |
| 860 | - console.error('Error saving calculation:', error); | |
| 750 | + // console.error('Error saving calculation:', error); | |
| 861 | 751 | alert('There was an error saving your calculation. Please try again.'); |
| 862 | 752 | } |
| 863 | 753 | }); |
| 864 | 754 | |
| @@ -916,9 +806,9 @@ | ||
| 916 | 806 | } else { |
| 917 | 807 | alert('Calculation loaded successfully.'); |
| 918 | 808 | } |
| 919 | 809 | } catch (error) { |
| 920 | - console.error('Error loading calculation:', error); | |
| 810 | + // console.error('Error loading calculation:', error); | |
| 921 | 811 | alert('There was an error loading your calculation. The saved data may be corrupted.'); |
| 922 | 812 | } |
| 923 | 813 | }); |
| 924 | 814 | |
| @@ -923,9 +813,9 @@ | ||
| 923 | 813 | }); |
| 924 | 814 | |
| 925 | 815 | // Conditional Logic |
| 926 | 816 | if (conditionalRules) { |
| 927 | - console.log('Conditional rules found:', conditionalRules); | |
| 817 | + // console.log('Conditional rules found:', conditionalRules); | |
| 928 | 818 | function evaluateCondition(val, operator, expected) { |
| 929 | 819 | try { |
| 930 | 820 | // Convert values for proper comparison |
| 931 | 821 | var compVal = val; |
| @@ -937,9 +827,9 @@ | ||
| 937 | 827 | compExpected = parseFloat(expected); |
| 938 | 828 | |
| 939 | 829 | // Check if we have valid numbers |
| 940 | 830 | if (isNaN(compVal) || isNaN(compExpected)) { |
| 941 | - console.warn('Invalid numeric comparison with NaN:', val, operator, expected); | |
| 831 | + // console.warn('Invalid numeric comparison with NaN:', val, operator, expected); | |
| 942 | 832 | return false; |
| 943 | 833 | } |
| 944 | 834 | } |
| 945 | 835 | |
| @@ -949,9 +839,9 @@ | ||
| 949 | 839 | return operator === 'is_checked' ? compVal === true : compVal === false; |
| 950 | 840 | } |
| 951 | 841 | |
| 952 | 842 | // Log the comparison |
| 953 | - console.log('Comparing:', compVal, operator, compExpected); | |
| 843 | + // console.log('Comparing:', compVal, operator, compExpected); | |
| 954 | 844 | |
| 955 | 845 | // Perform the comparison |
| 956 | 846 | switch (operator) { |
| 957 | 847 | case 'equal': return compVal == compExpected; |
| @@ -961,14 +851,14 @@ | ||
| 961 | 851 | case 'contains': return ('' + compVal).indexOf(compExpected) !== -1; |
| 962 | 852 | default: return false; |
| 963 | 853 | } |
| 964 | 854 | } catch (e) { |
| 965 | - console.error('Error evaluating condition:', e); | |
| 855 | + // console.error('Error evaluating condition:', e); | |
| 966 | 856 | return false; |
| 967 | 857 | } |
| 968 | 858 | } |
| 969 | 859 | $.each(conditionalRules, function(_, rule) { |
| 970 | - console.log('Processing rule:', rule); | |
| 860 | + // console.log('Processing rule:', rule); | |
| 971 | 861 | |
| 972 | 862 | // Improve field selection to handle both custom IDs and auto-generated IDs |
| 973 | 863 | var $ifField, $targetField; |
| 974 | 864 | |
| @@ -985,21 +875,21 @@ | ||
| 985 | 875 | // Try finding a field with a custom ID (king-calc-*) |
| 986 | 876 | $targetField = $calculator.find('[data-field-id="king-calc-' + rule.target_field + '"]'); |
| 987 | 877 | } |
| 988 | 878 | |
| 989 | - console.log('Condition field found:', $ifField.length > 0, 'Target field found:', $targetField.length > 0); | |
| 879 | + // console.log('Condition field found:', $ifField.length > 0, 'Target field found:', $targetField.length > 0); | |
| 990 | 880 | |
| 991 | 881 | // Log actual field IDs to help debug |
| 992 | 882 | if ($ifField.length > 0) { |
| 993 | - console.log('If field ID:', $ifField.data('field-id')); | |
| 883 | + // console.log('If field ID:', $ifField.data('field-id')); | |
| 994 | 884 | } |
| 995 | 885 | if ($targetField.length > 0) { |
| 996 | - console.log('Target field ID:', $targetField.data('field-id')); | |
| 886 | + // console.log('Target field ID:', $targetField.data('field-id')); | |
| 997 | 887 | } |
| 998 | 888 | |
| 999 | 889 | // If either field is not found, skip this rule |
| 1000 | 890 | if (!$ifField.length || !$targetField.length) { |
| 1001 | - console.warn('Could not find one or both fields for this rule, skipping'); | |
| 891 | + // console.warn('Could not find one or both fields for this rule, skipping'); | |
| 1002 | 892 | return true; // Continue to next rule |
| 1003 | 893 | } |
| 1004 | 894 | |
| 1005 | 895 | function applyRule() { |
| @@ -1006,9 +896,9 @@ | ||
| 1006 | 896 | var val; |
| 1007 | 897 | var type = $ifField.data('field-type'); |
| 1008 | 898 | |
| 1009 | 899 | // Log the field type to debug |
| 1010 | - console.log('Evaluating field type:', type); | |
| 900 | + // console.log('Evaluating field type:', type); | |
| 1011 | 901 | |
| 1012 | 902 | if (type === 'checkbox' || type === 'switch') { |
| 1013 | 903 | val = $ifField.find('input[type="checkbox"]').prop('checked'); |
| 1014 | 904 | } else if (type === 'radio') { |
| @@ -1017,12 +907,12 @@ | ||
| 1017 | 907 | val = $ifField.find('input, select').val(); |
| 1018 | 908 | } |
| 1019 | 909 | |
| 1020 | 910 | // Log the actual field value |
| 1021 | - console.log('Field value:', val, 'comparing with:', rule.value, 'using operator:', rule.operator); | |
| 911 | + // console.log('Field value:', val, 'comparing with:', rule.value, 'using operator:', rule.operator); | |
| 1022 | 912 | |
| 1023 | 913 | var result = evaluateCondition(val, rule.operator, rule.value); |
| 1024 | - console.log('Condition evaluation result:', result); | |
| 914 | + // console.log('Condition evaluation result:', result); | |
| 1025 | 915 | |
| 1026 | 916 | // Apply the action based on the result |
| 1027 | 917 | try { |
| 1028 | 918 | switch (rule.action) { |
| @@ -1061,18 +951,18 @@ | ||
| 1061 | 951 | case 'set_value': |
| 1062 | 952 | if (result) { |
| 1063 | 953 | var $input = $targetField.find('input, select'); |
| 1064 | 954 | $input.val(rule.set_value).trigger('change'); |
| 1065 | - console.log('Set value to:', rule.set_value); | |
| 955 | + // console.log('Set value to:', rule.set_value); | |
| 1066 | 956 | } |
| 1067 | 957 | break; |
| 1068 | 958 | } |
| 1069 | 959 | } catch (e) { |
| 1070 | - console.error('Error applying action:', e); | |
| 960 | + // console.error('Error applying action:', e); | |
| 1071 | 961 | } |
| 1072 | 962 | |
| 1073 | 963 | // Log the action taken |
| 1074 | - console.log('Applied action:', rule.action, 'with result:', result); | |
| 964 | + // console.log('Applied action:', rule.action, 'with result:', result); | |
| 1075 | 965 | } |
| 1076 | 966 | $ifField.on('change input', applyRule); |
| 1077 | 967 | |
| 1078 | 968 | // Also execute immediately once to set initial state |