/**
* Pricing Calculator
* JavaScript functionality for the Pricing Calculator widget
*/
(function($) {
"use strict";
/**
* Initialize the pricing calculator
*/
var initPricingCalculator = function() {
$('.king-pricing-calculator').each(function() {
var $calculator = $(this);
var calculatorId = $calculator.attr('id');
if ($calculator.data('initialized')) {
return;
}
$calculator.data('initialized', true);
// Calculator settings
var basePrice = parseFloat($calculator.data('base-price')) || 0;
var decimalPlaces = parseInt($calculator.data('decimal-places')) || 2;
var thousandSeparator = $calculator.data('thousand-separator') || ',';
var decimalSeparator = $calculator.data('decimal-separator') || '.';
var pricePrefix = $calculator.data('price-prefix') || '';
var priceSuffix = $calculator.data('price-suffix') || '';
// Live calculation mode
var isLiveMode = $calculator.hasClass('king-pricing-calculator--live');
// Cache selectors
var $fields = $calculator.find('.king-pricing-calculator__field');
var $totalPrice = $calculator.find('.king-pricing-calculator__total-price');
var $summaryItems = $calculator.find('.king-pricing-calculator__summary-items');
var $calculateButton = $calculator.find('.king-pricing-calculator__calculate-button');
// Debug info - log initial calculator settings
console.log('Calculator initialized with base price:', basePrice);
// Get ajaxurl from localized script if it exists, fallback to global
var ajaxUrl = (typeof king_addons_calculator_vars !== 'undefined') ? king_addons_calculator_vars.ajaxurl : (typeof ajaxurl !== 'undefined' ? ajaxurl : '');
// Get nonces from localized script
var addToCartNonce = (typeof king_addons_calculator_vars !== 'undefined') ? king_addons_calculator_vars.add_to_cart_nonce : '';
var sendEmailQuoteNonce = (typeof king_addons_calculator_vars !== 'undefined') ? king_addons_calculator_vars.send_email_quote_nonce : '';
// Debounce function for performance
var debounce = function(func, wait) {
var timeout;
return function() {
var context = this, args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function() {
func.apply(context, args);
}, wait);
};
};
// Sanitize potentially user-controlled strings before inserting into HTML.
// Uses DOMPurify for robust XSS protection.
var sanitizeHtml = function(value) {
if (typeof DOMPurify !== 'undefined') {
return DOMPurify.sanitize(String(value), {ALLOWED_TAGS: [], ALLOWED_ATTR: []});
}
// Fallback if DOMPurify not loaded
return String(value)
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
};
// Initialize field values and events
initFields($fields);
// Add accessibility attributes
addAccessibilityAttributes();
// Initial calculation
calculatePrice();
// Calculate button click event
if ($calculateButton.length && !isLiveMode) {
$calculateButton.on('click', calculatePrice);
}
// Initialize Pro feature handlers if Pro is active
if ($calculator.hasClass('king-pricing-calculator--pro')) {
initProFeatures($calculator);
}
/**
* Add ARIA attributes for accessibility
*/
function addAccessibilityAttributes() {
// Range sliders
$calculator.find('input[type="range"]').each(function() {
var $range = $(this);
var fieldLabel = $range.closest('.king-pricing-calculator__field').find('.king-pricing-calculator__field-label').text();
$range.attr({
'role': 'slider',
'aria-label': fieldLabel,
'aria-valuemin': $range.attr('min'),
'aria-valuemax': $range.attr('max'),
'aria-valuenow': $range.val()
});
// Update aria values on change
$range.on('input change', function() {
$range.attr('aria-valuenow', $range.val());
});
});
}
/**
* Initialize calculator fields with events
*/
function initFields($fields) {
$fields.each(function() {
var $field = $(this);
var fieldType = $field.data('field-type');
// Debug info - log field attributes
console.log('Field:', fieldType, 'Price Type:', $field.data('price-type'), 'Price:', $field.data('price'));
// Check if custom formula is used (Pro feature)
if ($field.data('price-type') === 'custom') {
// Show a one-time console message
if (!window.customFormulaMessageShown) {
console.info('Custom formula calculation requires Pro version.');
window.customFormulaMessageShown = true;
}
}
switch (fieldType) {
case 'number':
var $input = $field.find('input[type="number"]');
// Ensure default value is set
if ($input.val() === '') {
$input.val($input.attr('min') || 0);
}
// Debounce input for better performance
$input.on('input change', debounce(function() {
// Validate input
var value = parseFloat($input.val());
var min = parseFloat($input.attr('min'));
var max = parseFloat($input.attr('max'));
if (isNaN(value)) {
$input.val(min || 0);
value = parseFloat($input.val());
}
if (!isNaN(min) && value < min) {
$input.val(min);
} else if (!isNaN(max) && value > max) {
$input.val(max);
}
if (isLiveMode) {
calculatePrice();
}
}, 300));
break;
case 'range':
var $range = $field.find('input[type="range"]');
var $value = $field.find('.king-pricing-calculator__range-value');
// Ensure default value is set
if ($range.val() === '') {
$range.val($range.attr('min') || 0);
$value.text($range.val());
}
// Set initial range progress
updateRangeProgress($range);
// Use both input and change events without debounce for immediate feedback
$range.on('input', function() {
$value.text($range.val());
// Update range progress visual
updateRangeProgress($range);
// Always calculate on range change regardless of live mode
calculatePrice();
});
break;
case 'select':
var $select = $field.find('select');
// Ensure the first option is selected by default
if (!$select.find('option:selected').length) {
$select.find('option:first').prop('selected', true);
}
$select.on('change', function() {
if (isLiveMode) {
calculatePrice();
}
});
break;
case 'radio':
var $radios = $field.find('input[type="radio"]');
// Ensure at least one radio is checked
if (!$radios.filter(':checked').length) {
$radios.first().prop('checked', true);
}
$radios.on('change', function() {
if (isLiveMode) {
calculatePrice();
}
});
break;
case 'checkbox':
case 'switch':
var $checkbox = $field.find('input[type="checkbox"]');
$checkbox.on('change', function() {
if (isLiveMode) {
calculatePrice();
}
});
break;
}
});
}
/**
* Calculate the total price based on all field values
* Fields are processed in DOM order, applying each operation sequentially.
* This allows for proper calculation order (e.g., multiply first two values, then add third).
*/
function calculatePrice() {
try {
// Start with base price
var total = basePrice;
var summaryHtml = '';
// Debug info
console.log('Starting calculation with base price:', total);
// Advanced Formula will be applied after default calculation
// Process all fields in DOM order (sequential calculation)
$fields.each(function() {
var $field = $(this);
var fieldType = $field.data('field-type');
var priceType = $field.data('price-type');
var fieldLabel = $field.find('.king-pricing-calculator__field-label').text();
var fieldValue = 0;
var fieldPrice = 0;
var subTotal = 0;
var beforeOp = total;
try {
// Get field value and price based on field type
switch (fieldType) {
case 'number':
var $input = $field.find('input[type="number"]');
fieldValue = parseFloat($input.val());
fieldPrice = parseFloat($field.data('price'));
break;
case 'range':
var $range = $field.find('input[type="range"]');
fieldValue = parseFloat($range.val());
fieldPrice = parseFloat($field.data('price'));
break;
case 'select':
var $select = $field.find('select');
var $option = $select.find('option:selected');
fieldValue = $option.text();
fieldPrice = parseFloat($option.data('price'));
break;
case 'radio':
var $radio = $field.find('input[type="radio"]:checked');
if ($radio.length) {
fieldValue = $radio.siblings('label').text();
fieldPrice = parseFloat($radio.data('price'));
}
break;
case 'checkbox':
case 'switch':
var $checkbox = $field.find('input[type="checkbox"]');
if ($checkbox.is(':checked')) {
fieldValue = 'Yes';
fieldPrice = parseFloat($field.data('price'));
} else {
fieldValue = 'No';
fieldPrice = 0;
}
break;
}
// Apply the operation based on price type
if (priceType === 'add') {
// For number/range: multiply value by price per unit, then add
if (fieldType === 'number' || fieldType === 'range') {
if (!isNaN(fieldValue) && !isNaN(fieldPrice)) {
subTotal = fieldValue * fieldPrice;
total += subTotal;
}
} else {
// For select/radio/checkbox: add the price directly
if (!isNaN(fieldPrice)) {
subTotal = fieldPrice;
total += subTotal;
}
}
// Add to summary if there's a contribution
if (subTotal !== 0) {
summaryHtml += '
' +
'' + sanitizeHtml(fieldLabel) + ': ' + sanitizeHtml(fieldValue) + '' +
'+' + sanitizeHtml(formatPrice(subTotal)) + '' +
'
';
}
console.log('Field (add):', fieldLabel, 'Value:', fieldValue, 'Price:', fieldPrice, 'Subtotal:', subTotal, 'Total:', total);
} else if (priceType === 'multiply') {
// For number/range: multiply total by the field value
if (fieldType === 'number' || fieldType === 'range') {
if (!isNaN(fieldValue) && fieldValue !== 0) {
beforeOp = total;
total *= fieldValue;
summaryHtml += '' +
'' + sanitizeHtml(fieldLabel) + ': ×' + sanitizeHtml(fieldValue) + '' +
'' + sanitizeHtml(formatPrice(total - beforeOp)) + '' +
'
';
}
} else {
// For select/radio/checkbox: multiply total by the price
if (!isNaN(fieldPrice) && fieldPrice !== 0) {
beforeOp = total;
total *= fieldPrice;
summaryHtml += '' +
'' + sanitizeHtml(fieldLabel) + ': ' + sanitizeHtml(fieldValue) + ' (×' + sanitizeHtml(fieldPrice) + ')' +
'' + sanitizeHtml(formatPrice(total - beforeOp)) + '' +
'
';
}
}
console.log('Field (multiply):', fieldLabel, 'Value:', fieldValue, 'BeforeOp:', beforeOp, 'Total:', total);
} else if (priceType === 'custom') {
// In the free version, treat custom formula as add (fallback)
if (fieldType === 'number' || fieldType === 'range') {
if (!isNaN(fieldValue) && !isNaN(fieldPrice)) {
subTotal = fieldValue * fieldPrice;
total += subTotal;
summaryHtml += '' +
'' +
sanitizeHtml(fieldLabel) + ': ' + sanitizeHtml(fieldValue) +
' (Pro formula fallback)' +
'' +
'' + sanitizeHtml(formatPrice(subTotal)) + '' +
'
';
}
} else if (!isNaN(fieldPrice)) {
subTotal = fieldPrice;
total += subTotal;
summaryHtml += '' +
'' +
sanitizeHtml(fieldLabel) + ': ' + sanitizeHtml(fieldValue) +
' (Pro formula fallback)' +
'' +
'' + sanitizeHtml(formatPrice(subTotal)) + '' +
'
';
}
console.log('Field (custom/fallback):', fieldLabel, 'Added:', subTotal, 'Total:', total);
}
} catch (fieldError) {
console.error('Error processing field:', fieldLabel, fieldError);
}
});
// Advanced Formula override (Pro) after default calculation loops
if ($calculator.hasClass('king-pricing-calculator--advanced-formula')) {
var formulaType = $calculator.data('formulaType') || 'standard';
// Map fields for formula execution
var fieldsMap = {};
var aliasMap = {}; // Create a user-friendly alias map using custom field IDs
$fields.each(function() {
var $field = $(this);
var id = $field.data('field-id');
var type = $field.data('field-type');
var value;
if (type === 'checkbox' || type === 'switch') {
value = $field.find('input[type="checkbox"]').is(':checked');
} else if (type === 'radio') {
value = $field.find('input[type="radio"]:checked').val();
} else {
var v = $field.find('input, select').val();
var num = parseFloat(v);
value = isNaN(num) ? v : num;
}
fieldsMap[id] = value;
// If this is a custom field ID (starting with 'king-calc-'), create an alias
if (id.indexOf('king-calc-') === 0) {
var customId = id.replace('king-calc-', '');
aliasMap[customId] = value;
}
});
// For debugging custom formulas
console.log('Available field IDs:', fieldsMap);
console.log('User-friendly field aliases:', aliasMap);
// Apply chosen formula on the aggregated total
var newTotal = total;
if (formulaType === 'exponential') {
var expBase = parseFloat($calculator.data('exponentialBase')) || 1;
newTotal = Math.pow(total, expBase);
} else if (formulaType === 'logarithmic') {
var logBase = parseFloat($calculator.data('logarithmicBase')) || Math.E;
// Avoid log(0) or log of negative
newTotal = total > 0 ? Math.log(total) / Math.log(logBase) : 0;
} else if (formulaType === 'custom') {
var customCode = $calculator.data('customFormula') || '';
try {
// Security fix: Only allow safe mathematical operations
if (!isCustomFormulaSafe(customCode)) {
console.error('Custom formula contains unsafe code');
return;
}
// Pass both the full field map and user-friendly aliases
var fn = new Function('fields', 'basePrice', 'aliases', customCode);
newTotal = fn(fieldsMap, basePrice, aliasMap);
} catch (e) {
console.error('Custom formula error:', e);
}
function isCustomFormulaSafe(formula) {
// Only allow safe mathematical operations
var safePatterns = [
/^[0-9+\-*/().\s]+$/, // Basic math
/Math\.(abs|round|ceil|floor|min|max|pow|sqrt|sin|cos|tan|log|exp|PI|E)/g, // Safe Math functions
];
for (var i = 0; i < safePatterns.length; i++) {
if (safePatterns[i].test(formula)) {
return true;
}
}
// Check for dangerous patterns
var dangerousPatterns = [
/eval|Function|new|this|window|document|script|alert|prompt|confirm/g,
/[\[\]{}]/g, // Object/array notation
/\w+\s*\(/g, // Function calls (except Math functions already checked)
];
for (var i = 0; i < dangerousPatterns.length; i++) {
if (dangerousPatterns[i].test(formula)) {
return false;
}
}
return true;
}
}
// Override total with formula result
total = (typeof newTotal === 'number' && !isNaN(newTotal)) ? newTotal : total;
}
// Final check to prevent NaN
if (isNaN(total)) {
console.error('Total calculation resulted in NaN');
total = basePrice;
}
// Debug info
console.log('Final total:', total);
// Update the total price
$totalPrice.text(formatPrice(total));
// Update the summary items
$summaryItems.html(summaryHtml);
} catch(e) {
console.error('Calculation error:', e);
$totalPrice.text(formatPrice(basePrice));
}
}
/**
* Format a price number with proper separators
*/
function formatPrice(number) {
if (isNaN(number)) {
console.error('Attempting to format NaN as price');
number = 0;
}
var parts = number.toFixed(decimalPlaces).toString().split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, thousandSeparator);
return pricePrefix + parts.join(decimalSeparator) + priceSuffix;
}
/**
* Update the visual appearance of range slider progress
*/
function updateRangeProgress($range) {
var min = parseFloat($range.attr('min')) || 0;
var max = parseFloat($range.attr('max')) || 100;
var value = parseFloat($range.val()) || 0;
var progress = ((value - min) / (max - min)) * 100;
// Set CSS variable for the progress
$range.css('--range-progress', progress + '%');
}
});
};
/**
* Initialize Pro feature handlers for Pricing Calculator
* @param jQuery $calculator
*/
function initProFeatures($calculator) {
var calculatorId = $calculator.attr('id');
var $summaryItems = $calculator.find('.king-pricing-calculator__summary-items');
var $totalPrice = $calculator.find('.king-pricing-calculator__total-price');
// Use localized nonces if available, fallback to data attributes
var addToCartNonce = addToCartNonce || $calculator.data('addToCartNonce');
var sendEmailNonce = sendEmailQuoteNonce || $calculator.data('sendEmailNonce');
var recipientEmail = $calculator.data('recipientEmail');
var emailSubject = $calculator.data('emailSubject');
// Try to get conditional rules from data attribute, accounting for possible casing issues
var conditionalRules;
try {
// First try direct data attribute access
conditionalRules = $calculator.data('conditionalRules');
// If that doesn't work, try to get the raw attribute and parse it
if (!conditionalRules && $calculator.attr('data-conditional-rules')) {
console.log('Found data-conditional-rules attribute, trying to parse:', $calculator.attr('data-conditional-rules'));
conditionalRules = JSON.parse($calculator.attr('data-conditional-rules'));
}
console.log('Conditional rules loaded:', conditionalRules);
} catch (e) {
console.error('Error parsing conditional rules:', e);
}
// Add to Cart Integration
$calculator.find('.king-pricing-calculator-pro__add-to-cart-button').on('click', function() {
var price = parseFloat($totalPrice.text().replace(/[^0-9\.\-]/g, '')) || 0;
var productId = $(this).data('productId') || '';
var includeDetails = $(this).data('includeDetails') === 'yes';
var productType = productId ? 'specific' : 'dynamic';
var data = {
action: 'king_addons_add_to_cart',
nonce: addToCartNonce,
price: price,
product_type: productType,
product_id: productId,
quantity: 1,
use_as_budget: includeDetails
};
$.post(ajaxUrl, data, function(response) {
if (response.success) {
alert(response.data.message);
if (response.data.fragments) {
$.each(response.data.fragments, function(key, html) {
$(key).replaceWith(html);
});
}
} else {
alert(response.data.message || 'Error adding to cart.');
}
});
});
// Email Quote Option
var $emailButton = $calculator.find('.king-pricing-calculator-pro__email-button');
var $emailForm = $calculator.find('.king-pricing-calculator-pro__email-form');
$emailButton.on('click', function() {
$emailForm.toggle();
});
$emailForm.find('.king-pricing-calculator-pro__cancel-email-button').on('click', function() {
$emailForm.hide();
});
$emailForm.find('.king-pricing-calculator-pro__send-email-button').on('click', function() {
var name = $emailForm.find('#quote_name').val();
var email = $emailForm.find('#quote_email').val();
var message = $emailForm.find('#quote_message').val();
var quoteHtml = $summaryItems.html();
var totalHtml = 'Total' + $totalPrice.text() + '
';
var data = {
action: 'king_addons_send_email_quote',
nonce: sendEmailNonce,
name: name,
email: email,
message: message,
quote_data: quoteHtml + totalHtml,
recipient: recipientEmail,
subject: emailSubject
};
$.post(ajaxUrl, data, function(response) {
if (response.success) {
alert(response.data.message);
$emailForm.hide();
} else {
alert(response.data.message || 'Error sending quote.');
}
});
});
// Generate PDF Quote (print to PDF)
$calculator.find('.king-pricing-calculator-pro__pdf-button').on('click', function() {
// Create a more styled printable version with better formatting
var calculatorTitle = $calculator.find('.king-pricing-calculator__title').text() || document.title;
var calculatorDesc = $calculator.find('.king-pricing-calculator__description').text() || '';
var logo = $calculator.data('companyLogo') || '';
var logoHtml = logo ? '
' : '';
// Get current date in a nice format
var today = new Date();
var date = today.toLocaleDateString();
// Create a well-formatted HTML document for printing
var content = '' +
'' + calculatorTitle + ' - Quote' +
'' +
'' +
'' +
'';
// Add all line items
$summaryItems.find('.king-pricing-calculator__summary-item').each(function() {
var label = $(this).find('.king-pricing-calculator__summary-label').text();
var value = $(this).find('.king-pricing-calculator__summary-value').text();
content += '
' +
'' + label + '' +
'' + value + '' +
'
';
});
// Add the total
content += '
' +
'' +
'Total' +
'' + $totalPrice.text() + '' +
'
' +
'';
// Open a new window, write the content, and trigger print
var win = window.open('', '_blank');
win.document.write(content);
win.document.close();
// Slight delay to ensure content is loaded before printing
setTimeout(function() {
win.focus();
win.print();
// Don't close automatically to allow users to save as PDF
// win.close();
}, 250);
});
// Save/Load Calculations using localStorage
var storageKey = calculatorId + '_data';
$calculator.find('.king-pricing-calculator-pro__save-button').on('click', function() {
try {
var fieldsData = {};
var hasValues = false;
// Collect all field values
$calculator.find('.king-pricing-calculator__field').each(function() {
var $field = $(this);
var id = $field.data('field-id');
var type = $field.data('field-type');
var val;
if (type === 'checkbox' || type === 'switch') {
val = $field.find('input[type="checkbox"]').prop('checked');
} else if (type === 'radio') {
val = $field.find('input[type="radio"]:checked').val();
} else {
val = $field.find('input, select').val();
}
if (val !== undefined && val !== null && val !== '') {
hasValues = true;
}
fieldsData[id] = val;
});
// Add metadata
fieldsData._meta = {
date: new Date().toISOString(),
total: $totalPrice.text(),
calculatorId: calculatorId
};
if (!hasValues) {
alert('No values to save. Please fill in the calculator fields first.');
return;
}
// Save to localStorage
localStorage.setItem(storageKey, JSON.stringify(fieldsData));
alert('Calculation saved successfully.');
} catch (error) {
console.error('Error saving calculation:', error);
alert('There was an error saving your calculation. Please try again.');
}
});
$calculator.find('.king-pricing-calculator-pro__load-button').on('click', function() {
try {
var saved = localStorage.getItem(storageKey);
if (!saved) {
alert('No saved calculation found for this calculator.');
return;
}
var fieldsData = JSON.parse(saved);
var foundFields = false;
// Check if metadata matches this calculator
if (fieldsData._meta && fieldsData._meta.calculatorId && fieldsData._meta.calculatorId !== calculatorId) {
alert('The saved calculation is for a different calculator. Unable to load.');
return;
}
// Apply the saved values to fields
$.each(fieldsData, function(id, val) {
// Skip metadata
if (id === '_meta') return;
var $field = $calculator.find('[data-field-id="' + id + '"]');
if ($field.length) {
foundFields = true;
var type = $field.data('field-type');
if (type === 'checkbox' || type === 'switch') {
$field.find('input[type="checkbox"]').prop('checked', val);
} else if (type === 'radio') {
$field.find('input[type="radio"]').filter('[value="' + val + '"]').prop('checked', true);
} else {
$field.find('input, select').val(val).trigger('change');
}
}
});
if (!foundFields) {
alert('No saved values could be applied to this calculator.');
return;
}
// Recalculate with the loaded values
calculatePrice();
// Show success message with saved date if available
var savedDate = fieldsData._meta && fieldsData._meta.date ?
new Date(fieldsData._meta.date).toLocaleString() : '';
if (savedDate) {
alert('Calculation loaded successfully. (Saved on: ' + savedDate + ')');
} else {
alert('Calculation loaded successfully.');
}
} catch (error) {
console.error('Error loading calculation:', error);
alert('There was an error loading your calculation. The saved data may be corrupted.');
}
});
// Conditional Logic
if (conditionalRules) {
console.log('Conditional rules found:', conditionalRules);
function evaluateCondition(val, operator, expected) {
try {
// Convert values for proper comparison
var compVal = val;
var compExpected = expected;
// For numeric comparisons, explicitly convert to numbers
if (operator === 'greater' || operator === 'less') {
compVal = parseFloat(val);
compExpected = parseFloat(expected);
// Check if we have valid numbers
if (isNaN(compVal) || isNaN(compExpected)) {
console.warn('Invalid numeric comparison with NaN:', val, operator, expected);
return false;
}
}
// Special handling for boolean values
if (operator === 'is_checked' || operator === 'is_not_checked') {
// These operators don't use the expected value, they check the val directly
return operator === 'is_checked' ? compVal === true : compVal === false;
}
// Log the comparison
console.log('Comparing:', compVal, operator, compExpected);
// Perform the comparison
switch (operator) {
case 'equal': return compVal == compExpected;
case 'not_equal': return compVal != compExpected;
case 'greater': return compVal > compExpected;
case 'less': return compVal < compExpected;
case 'contains': return ('' + compVal).indexOf(compExpected) !== -1;
default: return false;
}
} catch (e) {
console.error('Error evaluating condition:', e);
return false;
}
}
$.each(conditionalRules, function(_, rule) {
console.log('Processing rule:', rule);
// Improve field selection to handle both custom IDs and auto-generated IDs
var $ifField, $targetField;
// Try to find the "if" field, first by exact ID, then by custom ID
$ifField = $calculator.find('[data-field-id="' + rule.if_field + '"]');
if (!$ifField.length) {
// Try finding a field with a custom ID (king-calc-*)
$ifField = $calculator.find('[data-field-id="king-calc-' + rule.if_field + '"]');
}
// Try to find the target field, first by exact ID, then by custom ID
$targetField = $calculator.find('[data-field-id="' + rule.target_field + '"]');
if (!$targetField.length) {
// Try finding a field with a custom ID (king-calc-*)
$targetField = $calculator.find('[data-field-id="king-calc-' + rule.target_field + '"]');
}
console.log('Condition field found:', $ifField.length > 0, 'Target field found:', $targetField.length > 0);
// Log actual field IDs to help debug
if ($ifField.length > 0) {
console.log('If field ID:', $ifField.data('field-id'));
}
if ($targetField.length > 0) {
console.log('Target field ID:', $targetField.data('field-id'));
}
// If either field is not found, skip this rule
if (!$ifField.length || !$targetField.length) {
console.warn('Could not find one or both fields for this rule, skipping');
return true; // Continue to next rule
}
function applyRule() {
var val;
var type = $ifField.data('field-type');
// Log the field type to debug
console.log('Evaluating field type:', type);
if (type === 'checkbox' || type === 'switch') {
val = $ifField.find('input[type="checkbox"]').prop('checked');
} else if (type === 'radio') {
val = $ifField.find('input[type="radio"]:checked').val();
} else {
val = $ifField.find('input, select').val();
}
// Log the actual field value
console.log('Field value:', val, 'comparing with:', rule.value, 'using operator:', rule.operator);
var result = evaluateCondition(val, rule.operator, rule.value);
console.log('Condition evaluation result:', result);
// Apply the action based on the result
try {
switch (rule.action) {
case 'show':
// Use CSS display property to properly show/hide
if (result) {
$targetField.css('display', ''); // Use default display
} else {
$targetField.css('display', 'none');
}
break;
case 'hide':
// Use CSS display property to properly show/hide (inverse of show)
if (!result) {
$targetField.css('display', ''); // Use default display
} else {
$targetField.css('display', 'none');
}
break;
case 'enable':
$targetField.find('input, select').prop('disabled', !result);
if (!result) {
$targetField.addClass('king-pricing-calculator__field--disabled');
} else {
$targetField.removeClass('king-pricing-calculator__field--disabled');
}
break;
case 'disable':
$targetField.find('input, select').prop('disabled', result);
if (result) {
$targetField.addClass('king-pricing-calculator__field--disabled');
} else {
$targetField.removeClass('king-pricing-calculator__field--disabled');
}
break;
case 'set_value':
if (result) {
var $input = $targetField.find('input, select');
$input.val(rule.set_value).trigger('change');
console.log('Set value to:', rule.set_value);
}
break;
}
} catch (e) {
console.error('Error applying action:', e);
}
// Log the action taken
console.log('Applied action:', rule.action, 'with result:', result);
}
$ifField.on('change input', applyRule);
// Also execute immediately once to set initial state
applyRule();
});
}
}
// Initialize on document ready
$(document).ready(function() {
initPricingCalculator();
});
// Initialize after Elementor frontend init
$(window).on('elementor/frontend/init', function() {
if (typeof elementorFrontend !== 'undefined') {
elementorFrontend.hooks.addAction('frontend/element_ready/king-addons-pricing-calculator.default', function() {
initPricingCalculator();
});
}
});
})(jQuery);